On the project in my company I saw a couple of times people creating a struct that contains only one element.
the latest one is added, in this example ipAddr is another struct( a good explanation to the case when ipAddr is an array is given by 'Frerich Raabe' but unfortunately thats not the case here)
typedef struct
{
ipAddr ip;
} Record;
I guess if the code is changing and in its beginning this makes sense since more fields can be easily added and the code can be easily manipulated to support the new fields, but this is a project started a long time ago written according to a design so I dont think its the issue here.
Why would one create a struct of one field then?
I can think of a couple reasons:
In case more fields may be needed later. This is somewhat common.
To deliberately make the outer type incompatible with the inner type.
For an example of the second, imagine this:
typedef struct
{
char postal_code[12];
} Destination;
In this case, the Destination is fully specified by the postal code, yet this will let us define functions like this:
int deliver(const char* message, const Destination* to);
This way, no user can inadvertently call the function with the two arguments reversed, which they could easily do if they were both plain strings.
A common reason for a struct with just one field is that the single field is an array, and you'd like to be able to define functions returning such array values. Consider e.g.
typedef unsigned char ipAddr[4];
void f(ipAddr ip); /* OK */
ipAddr g(void); /* Compiler barfs: cannot return array. */
This can be resolved by introducing a struct with a single member of type ipAddr:
typedef unsigned char ipAddr[4];
typedef struct {
ipAddr ip;
} Record;
void f(Record ip); /* OK */
Record g(void); /* Also OK: structs can be returned by value. */
However, even passing arrays to functions is problematic: you don't actually pass the array, you pass a pointer (the type "decays" into a pointer). Imagine f declared above would need to create a copy of the given IP address:
typedef unsignd char ipAddr[4];
void f(ipAddr ip) {
ipAddr *a = malloc(sizeof(ip));
/* ... */
}
This only happens to work with 32bit builds because the size of a pointer is the same (4 bytes) as the size of an array of four unsigned char values. A 64bit build (or a differently sized array) would exhibit a bug, either allocating too much or too little memory. This happens because inside f, ip is of type unsigned char *, i.e.a pointer. A struct helps with this, since it doesn't decay.
Related
I have two structs in a library I cannot change. p.e:
struct{
uint8_t test;
uint8_t data[8];
}typedef aStruct;
struct{
uint8_t value;
uint8_t unimportant_stuff;
char data[8];
}typedef bStruct;
aStruct a;
bStruct b;
In my application there is a process that permantently refreshs my aStruct's.
Now I have a buffer of bStruct's I want to keep updated as well.
The data[] array is the important field. I don't really care about the other values of the structs.
I already made sure, that on that specific system where the code runs on, a "char" is 8Bits as well.
Now I'd like to make the "b.data" array point to exactly the same values as my "a.data" array. So if the process refreshs my aStruct, the values in my bStruct are up to date as well.
Therefore that in C an array is only a pointer to the first element, I thought something like this must be possible:
b.data = a.data
But unfortunately this gives me the compiler-error:
error: assignment to expression with array type
Is there a way to do what I intend to do?
Thanks in advance
Okay, according to the input I got from you guys, I think it might be the best thing to redesign my application.
So instead of a buffer of bStruct's I might use a buffer of aStruct*. This makes sure my buffer is always up to date. And then if I need to do something with an element of the buffer, I will write a short getter-function which copies the data from that aStruct* into a temporary bStruct and returns it.
Thanks for your responses and comments.
If you want b.data[] array to point to exactly the same values, then you can make data of b a char* and make it point to a's data.
Something like
struct{
uint8_t value;
uint8_t unimportant_stuff;
char* data;
}typedef bStruct;
and
b.data = a.data;
But, keep in mind, this means that b.data is pointing at the same memory location as a.data and hence, changing values of b.data would change values of a.data also.
There is another way of doing this. It is by copying all the values of a.data into b.data. Then, b.data would merely contain the same values as a.data, but it would point to different memory locations.
This can either be done by copying one by one. In a for loop for all the 8 elements.
Or, to use memcpy()
NOTE
Arrays cannot be made to point to another memory locations. As they are non modifiable l-value. If you cannot modify the structs, then you have to use the second method.
What you are asking is not possible when you can not modify the existing struct definitions. But you can still automate the functionality with a bit of OO style programming on your side. All of the following assumes that the data fields in the structs are of same length and contain elements of same size, as in your example.
Basically, you wrap the existing structs with your own container. You can put this in a header file:
/* Forward declaration of the wrapper type */
typedef struct s_wrapperStruct wrapperStruct;
/* Function pointer type for an updater function */
typedef void (*STRUCT_UPDATE_FPTR)(wrapperStruct* w, aStruct* src);
/* Definition of the wrapper type */
struct s_wrapperStruct
{
STRUCT_UPDATE_FPTR update;
aStruct* ap;
bStruct* bp;
};
Then you can can create a factory style module that you use to create your synced struct pairs and avoid exposing your synchronization logic to uninterested parties. Implement a couple of simple functions.
/* The updater function */
static void updateStructs(wrapperStruct* w, aStruct* src)
{
if ( (w != NULL) && (src != NULL) )
{
/* Copy the source data to your aStruct (or just the data field) */
memcpy(w->ap, src, sizeof(aStruct));
/* Sync a's data field to b */
sync(w); /* Keep this as a separate function so you can make it optional */
}
}
/* Sync the data fields of the two separate structs */
static void sync(wrapperStruct* w)
{
if (w != NULL)
{
memcpy(w->bp->data, w->ap->data, sizeof(w->bp->data));
}
}
Then in your factory function you can create the wrapped pairs.
/* Create a wrapper */
wrapperStruct syncedPair = { &updateStructs, &someA, &someB };
You can then pass the pair where you need it, e.g. the process that is updating your aStruct, and use it like this:
/* Pass new data to the synced pair */
syncedPair.update( &syncedPair, &newDataSource );
Because C is not designed as an OO language, it does not have a this pointer and you need to pass around the explicit wrapper pointer. Essentially this is what happens behind the scenes in C++ where the compiler saves you the extra trouble.
If you need to sync a single aStruct to multiple bStructs, it should be quite simple to change the bp pointer to a pointer-to-array and modify the rest accordingly.
This might look like an overly complicated solution, but when you implement the logic once, it will likely save you from some manual labor in maintenance.
I'm wondering for a solution to the below problem. Please help.
Problem:
struct s{
int a;
int b;
}st;
I want a function to initialize the values at runtime. The problem is that I want to make it generic, so I want to pass the member name as input to the function and get it initialized.
fun_init(char* mem, int val)
{
// Find offset of the member variable in struct 'st'
// Assign the value
}
One straight solution is to use string comparision on the member name. But if I happen to add some extra variables at a later time, I'll have to modify the function, which I don't want.
Hope I was able to frame the ques clearly.
Thanks
C does not provide a way to find a symbol by name. See this thread for more information.
The simplest solution here is to use an associative array.
Read this thread if you need to mix value-types. (In your example, all value types are int, so you might not need this.)
void fun_init(int *storage, int val) {
*storage = val;
}
void something_else(void) {
struct s {
int a;
int b;
} st;
fun_init(&st.a, 42);
}
However, if you need to dynamically determine the key name, you are doing something wrong. If you need to store key/value pairs, perhaps you would be interested in the hashtable.
I'm guessing you want to initialize struct from either user input or persistency.
A solution involves creating an associative array as mentioned by #Domi.
The array is filled with key/value pairs such as (const char*, unsigned).
The key is the name of struct member and the value is the offset from the start of the struct.
Each struct will need to have a function that initializes the above array. You can get an offset to a member via the offsetof macro.
This will NOT work with structs that have bit fields (sub byte named members).
Is it possible to create a generic Vector like data structure in C, with out using heap. Basically I need a array data type but a more generalized version on if it.
typedef struct {
/* some data types*/
}TYPE1;
typedef struct {
/* some data types*/
}TYPE2;
typedef struct _GCACHE_T
{
const int element_size;
const int count;
struct _ELEMENT {
UBYTE data[element_size];
BOOLEAN is_valid;
}element[count];
}GCACHE_T;
GCACHE_T f_cache1 = {sizeof(TYPE1), 15, {0} };
GCACHE_T f_cache2 = {sizeof(TYPE2), 10, {0} };
The above code will not compile but I have provided it for a better clarity on my requirement.
This would have been easy implemted provided heap memory was allowed to use. Since the code is meant for small micros heap memory usage is not allowed.
I could have used right away, but just checking if it can be done in a generic way.
TYPE1 f_cache1[15];
TYPE2 f_cache2[10];
The Vector will not grow in size. I could have also used a union but there is a memory trade off so not willing to use it.
Such parametric (template, generic) types are not supported by C. You can take an approach similar to the one used by the BSD socket subsystem. There different network addresses (e.g. IP address and TCP/UDP port number) are stored in structures of varying size (depending on the address family, e.g. IPv4 structures are shorter than IPv6 ones) but with similar layout in the beginning. Whenever an address is required, a pointer to the generic struct sockaddr type is passed instead and the correct structure type is inferred from the address family of the socket.
C supports the so-called flexible array members, but it cannot be simply applied to your case because not only is the number of struct _ELEMENT entries different, but the size of those elements could differ depending on the value of element_size. This makes it hard to compute the address of cache.element[i].data[j] in a portable way whithout refering to the actual type. What you can do is put an additional field in the beginning of the GCACHE_T type that helps you identify the true size of struct _ELEMENT:
typedef struct _GCACHE_T
{
int element_size;
int count;
size_t element_stride;
struct _ELEMENT {
BOOLEAN is_valid;
UBYTE data[];
} element[];
} GCACHE_T;
element_stride keeps the size of the concrete element type (including any padding). Note that is_valid is moved before data[] as C allows only the last element of a structure to be a flexible one.
You would then create specific types, e.g.
typedef struct _GCACHE_TYPE1_15_T
{
int element_size;
int count;
size_t element_stride;
struct {
BOOLEAN is_valid;
UBYTE data[sizeof(TYPE1)];
} element[15];
} GCACHE_TYPE1_15_T;
GCACHE_TYPE1_15_T f_cache1 = {
sizeof(TYPE1),
15,
// An awful hack to obtain the size of a structure member
sizeof(((GCACHE_TYPE1_15_T *)0)->element[0])
};
do_something((GCACHE_T *)&f_cache1);
Macros would come handy if you need to declare many different cache types. Now in do_something() you can compute the address of f_cache1.element[i].data[j] because you know the offset of the data field inside struct _ELEMENT and you can compute the offset of element[i] because the size of a single element is stored in the element_stride field.
Yeah, I know, it is a real pain... And I am not sure how much of the pointer arithmetic required works on a Harvard architecture device like PIC.
I'm really new to C programming and I'm still trying to understand the concept of using pointers and using typedef structs.
I have this code snippet below that I need to use in a program:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
}* pStudentRecord;
I'm not exactly sure what this does - to me it seems similar as using interfaces in Objective-C, but I don't think that's the case.
And then I have this line
pStudentRecord* g_ppRecords;
I basically need to add several pStudentRecord to g_ppRecords based on a number. I understand how to create and allocate memory for an object of type pStudentRecord, but I'm not sure how to actually add multiple objects to g_ppRecords.
defines a pointer to the struct described within the curly bracers, here is a simpler example
typedef struct {
int x;
int y;
}Point,* pPoint;
int main(void) {
Point point = {4,5};
pPoint point_ptr = &point;
printf("%d - %d\n",point.x,point_ptr->x);
pPoint second_point_ptr = malloc(sizeof(Point));
second_point_ptr->x = 5;
free(second_point_ptr);
}
The first declares an unnamed struct, and a type pStudentRecord that is a pointer to it. The second declares g_ppRecords to be a pointer to a pStudentRecord. In other words, a pointer to a pointer to a struct.
It's probably easier to think of the second as an "array of pointers". As such, g_ppRecords[0] may point to a pStudentRecord and g_ppRecords[1] to another one. (Which, in turn, point to a record struct.)
In order to add to it, you will need to know how it stores the pointers, that is, how one might tell how many pointers are stored in it. There either is a size somewhere, which for size N, means at least N * sizeof(pStudentRecord*) of memory is allocated, and g_ppRecords[0] through g_ppRecords[N-1] hold the N items. Or, it's NULL terminated, which for size N, means at least (N+1) * sizeof(pStudentRecord*) of memory is allocated and g_ppRecords[0] through g_ppRecords[N-1] hold the N items, and g_ppRecords[N] holds NULL, marking the end of the string.
After this, it should be straightforward to create or add to a g_ppRecords.
A struct is a compound data type, meaning that it's a variable which contains other variables. You're familiar with Objective C, so you might think of it as being a tiny bit like a 'data only' class; that is, a class with no methods. It's a way to store related information together that you can pass around as a single unit.
Typedef is a way for you to name your own data types as synonyms for the built-in types in C. It makes code more readable and allows the compiler to catch more errors (you're effectively teaching the compiler more about your program's intent.) The classic example is
typedef int BOOL;
(There's no built-in BOOL type in older ANSI C.)
This means you can now do things like:
BOOL state = 1;
and declare functions that take BOOL parameters, then have the compiler make sure you're passing BOOLs even though they're really just ints:
void flipSwitch(BOOL isOn); /* function declaration */
...
int value = 0;
BOOL boolValue = 1;
flipSwitch(value); /* Compiler will error here */
flipSwitch(boolValue); /* But this is OK */
So your typedef above is creating a synonym for a student record struct, so you can pass around student records without having to call them struct StudentRecord every time. It makes for cleaner and more readable code. Except that there's more to it here, in your example. What I've just described is:
typedef struct {
char * firstName;
char * lastName;
int id;
float mark;
} StudentRecord;
You can now do things like:
StudentRecord aStudent = { "Angus\n", "Young\n", 1, 4.0 };
or
void writeToParents(StudentRecord student) {
...
}
But you've got a * after the typedef. That's because you want to typedef a data type which holds a pointer to a StudentRecord, not typedef the StudentRecord itself. Eh? Read on...
You need this pointer to StudentRecord because if you want to pass StudentRecords around and be able to modify their member variables, you need to pass around pointers to them, not the variables themselves. typedefs are great for this because, again, the compiler can catch subtle errors. Above we made writeToParents which just reads the contents of the StudentRecord. Say we want to change their grade; we can't set up a function with a simple StudentRecord parameter because we can't change the members directly. So, we need a pointer:
void changeGrade(StudentRecord *student, float newGrade) {
student->mark = newGrade;
}
Easy to see that you might miss the *, so instead, typedef a pointer type for StudentRecord and the compiler will help:
typedef struct { /* as above */ } *PStudentRecord;
Now:
void changeGrade(PStudentRecord student, float newGrade) {
student->mark = newGrade;
}
It's more common to declare both at the same time:
typedef struct {
/* Members */
} StudentRecord, *PStudentRecord;
This gives you both the plain struct typedef and a pointer typedef too.
What's a pointer, then? A variable which holds the address in memory of another variable. Sounds simple; it is, on the face of it, but it gets very subtle and involved very quickly. Try this tutorial
This defines the name of a pointer to the structure but not a name for the structure itself.
Try changing to:
typedef struct
{
char* firstName;
char* lastName;
int id;
float mark;
} StudentRecord;
StudentRecord foo;
StudentRecord *pfoo = &foo;
Often stacks in C are dependent upon datatype used to declare them. For example,
int arr[5]; //creates an integer array of size 5 for stack use
char arr[5]; //creates a character array of size 5 for stack use
are both limited to holding integer and character datatypes respectively and presumes that the programmer knows what data is generated during the runtime. What if I want a stack which can hold any datatype?
I initially thought of implementing it as a union, but the approach is not only difficult but also flawed. Any other suggestions?
I would use a structure like this:
struct THolder
{
int dataType; // this is a value representing the type
void *val; // this is the value
};
Then use an array of THolder to store your values.
This is really just a variant of Pablo Santa Cruz' answer, but I think it looks neater:
typedef enum { integer, real, other } type_t;
typedef struct {
type_t type;
union {
int normal_int; /* valid when type == integer */
double large_float; /* valid when type == real */
void * other; /* valid when type == other */
} content;
} stack_data_t;
You still need to use some way to explicitly set the type of data stored in each element, there is no easy way around that.
You could look into preprocessor magic relying on the compiler-dependent typeof keyword to do that automagically, but that will probably not do anything but ruin the portability.
Some people have suggested a void* member. In addition to that solution I'd like to offer an alternative (assuming your stack is a linked list of heap-allocated structures):
struct stack_node
{
struct stack_node *next;
char data[];
};
The data[] is a C99 construct. data must be the last member; this takes advantage of the fact that we can stuff arbitrary quantities after the address of the struct. If you're using non-C99 compiler you might have to do some sketchy trick like declare it as data[0].
Then you can do something like this:
struct stack_node*
allocate_stack_node(size_t extra_size)
{
return malloc(sizeof(struct stack_node) + extra_size);
}
/* In some other function... */
struct stack_node *ptr = allocate_stack_node(sizeof(int));
int *p = (int*)ptr->data;
If this looks ugly and hacky, it is... But the advantage here is that you still get the generic goodness without introducing more indirection (thus slightly quicker access times for ptr->data than if it were void* pointing to a different location from the structure.)
Update: I'd also like to point out that the code sample I give may have problems if your machine happens to have different alignment requirements for int than char. This is meant as an illustrative example; YMMV.
You could use macros and a "container" type to reduce "type" from being per-element, to whole-container. (C99 code below)
#define GENERIC_STACK(name, type, typeid, elements) \
struct name##_stack { \
unsigned int TypeID; \
type Data[elements]; \
} name = { .TypeID = typeid }
Of course, your "TypeID" would have to allow every possible agreed-upon type you expect; might be a problem if you intend to use whole structs or other user-defined types.
I realize having a uniquely named struct type for every variable is odd and probably not useful... oops.
I created an library that works for any data type:
List new_list(int,int);
creates new list eg:
List list=new_list(TYPE_INT,sizeof(int));
//This will create an list of integers
Error append(List*,void*);
appends an element to the list. *Append accpts two pointers as an argument, if you want to store pointer to the list don't pass the pointer by pointer
eg:
//using the int list from above
int a=5;
Error err;
err=append(&list,&a)
//for an list of pointers
List listptr=new_list(TYPE_CUSTOM,sizeof(int*));
int num=7;
int *ptr=#
append(&listptr,ptr);
//for list of structs
struct Foo
{
int num;
float *ptr;
};
List list=new_list(TYPE_CUSTOM,sizeof(struct Foo));
struct Foo x;
x.num=9;
x.ptr=NULL;
append(&list,&x);
Error get(List*,int);
Gets data at index specified. When called list's current poiter will point to the data.
eg:
List list=new_list(TYPE_INT,sizeof(int));
int i;
for(i=1;i<=10;i++)
append(&list,&i);
//This will print the element at index 2
get(&list,2);
printf("%d",*(int*)list.current);
Error pop(List*,int);
Pops and element from the specified index
eg:
List list=new_list(TYPE_INT,sizeof(int));
int i;
for(i=1;i<=10;i++)
append(&list,&i);
//element in the index 2 will be deleted,
//the current pointer will point to a location that has a copy of the data
pop(&list,2);
printf("%d",*(int*)list.current);
//To use the list as stack, pop at index list.len-1
pop(&list,list.len-1);
//To use the list as queue, pop at index 0
pop(&list,0);
Error merge(List ,List);
Merges two list of same type. If types are different will return a error message in the Error object it returns;
eg:
//Merge two elements of type int
//List 2 will come after list 1
Error err;
err=merge(&list1,&list2);
Iterator get_iterator(List*);
Get an iterator to an list. when initialized will have a pointer to the first element of the list.
eg:
Iterator ite=get_iterator(&list);
Error next(Iterator*);
Get the next element of the list.
eg:
//How to iterate an list of integers
Iterator itr;
for(itr=get_iterator(&list); ite.content!=NULL; next(ite))
printf("%d",*(int*)ite.content);
https://github.com/malayh/C-List