I was surprised when gcc -Wall compiled this without warning. Is this really legitimate C? What are the risks of writing code like this?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a;
int b;
} MyStruct;
int main(void) {
MyStruct *s = malloc(sizeof(*s)); // as opposed to malloc(sizeof(MyStruct))
s->a = 5;
printf("%d\n", s->a);
}
Not only it's legitimate, it's even preferable to the alternative. This way you let the compiler deduce the actual type instead of doing it manually.
sizeof is evaluated at compile time. In this context, *s resolves to the type of *s, it does not dereference the pointer.
This is the canonical way of using sizeof. If you used sizeof(int) you leave an opening for an error should the type change (in this case, probably unlikely, but still.)
Writing
MyStruct *s = malloc(sizeof(*s));
has exactly the same effect as
MyStruct *s = malloc(sizeof(MyStruct));
except that now you only write MyStruct once. That is, the object you're allocating has its source type determined automatically, which reduces the chances of errors.
For example - it has happened to me - you start with a MyStruct. Then you decide you need also a different MyStruct for different purposes. So you end up with two different structures, MyStruct and AnotherStruct.
Then you refactor your code and change some variables from MyStruct to AnotherStruct, and end up with
AnotherStruct *s = malloc(sizeof(MyStruct));
which might actually work in several circumstances, or for a long time, until you make another little and, at that point, completely unrelated change in either structure. At that point your code goes kaboom.
E.g.
typedef struct {
int a;
int b;
} StructA;
typedef struct {
int a;
int b;
int c;
} StructB;
int main() {
// No problem here except wasted space
StructA *s = malloc(sizeof(StructB));
// t->c dwells in undefined country
StructB *t = malloc(sizeof(StructA));
}
Related
I have the following struct that is defined in the following way
typedef struct _abcd {
int a;
unsigned long b;
void (*c)(int);
int d;
} abcd_t, *abcd;
Now i have the following code
static abcd foo
int set_size(int size){
foo = malloc(sizeof(abcd) * size);
}
This code for some reason gives me segfault when accessing some of the properties of array members.
But i have noticed that if i change the malloc line to the following - it fixes the issue
foo = malloc(sizeof(foo[0]) * size);
I find it strange as obviously sizeof(foo[0]) = sizeof(abcd)
So what is exactly the difference here?
Thanks
obviously sizeof(foo[0]) = sizeof(abcd)
It is not the same since you typedefed abcd to be a *pointer* to struct _abcd.
Use
foo = malloc(sizeof(*foo) * size);
to have robust code even if the type of foo should change at some point.
Your
foo = malloc(sizeof(foo[0]) * size);
is essentially the same since foo[0] is just syntactic sugar for *(foo + 0) which becomes *foo.
The bug is you're allocating sizeof(abcd) and that's a pointer, not a struct. You want sizeof(abcd_t) or sizeof(*abcd).
It's sometimes necessary to cast a data structure into a pointer so that the data can be sent, for example, over an interface, or written out to some other stream. In these cases, I usually do something like this:
typedef struct {
int field1;
char field2;
} testStruct;
int main()
{
char *buf;
testStruct test;
buf = (char *)&test;
// write(buf, sizeof(test)) or whatever you need to do
return 0;
}
Recently in some microprocessor code, however, I saw something similar to this:
typedef struct {
int field1;
char field2;
} testStruct;
int main()
{
char buf[5];
testStruct test;
*(testStruct *)buf = test;
// write(buf, sizeof(test)) or whatever you need to do
return 0;
}
To me, the former feels a little more safe. You just have one pointer, and you assign the address of the structure to the pointer.
In the latter case, it seems like if you allocate the wrong size to the array buf by accident, you'll end up with undefined behavior, or a segfault.
With optimizations on, I get a -Wstrict-aliasing warning from gcc. However, again, this code runs on a microprocessor, so is there something I might be missing there?
There's no pointers in the structures, or anything, it's very straight forward.
(testStruct *)buf may generate a mis-aligned address for a testStruct leading to a bus fault. Do not use.
A union is better. It helps cope with anti-aliasing issues as well as alignment ones.
Also see #Steve Summit's good comment.
Consider a master type like testStruct_all.
typedef struct { // OP's structure
int field1;
char field2;
} testStruct1;
typedef struct { // Perhaps another structure to send
double field1;
char field2;
} testStruct2;
// A union of all possible structures used in this app
typedef union {
testStruct1 tS1;
testStruct2 tS2;
char buf[1];
} testStruct_all;
int main(void) {
testStruct_all ux;
foo(&ux.tS1); // populate ux.tSn of choice.
write(ux.buf, sizeof ux.tS1);
read(ux.buf, sizeof ux.tS1);
// the union insures alignment and avoids AA issues
bar(&ux.tS1);
return 0;
}
write() usually accepts a void * #user58697, so code could drop the buf member and use:
write(&ux, sizeof ux.tS1); // or whatever you need to do
I have this struct
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
Now I need to create an instance of this struct. I googled this problem and found that I have to use something like this
typedef struct FluxCapacitor{
unsigned char* c_string
unsigned int value;
};
But I dont really understand the next step with malloc(). Can someone explain it to me?
You do not need malloc() to create an instance of a struct. And I would recommend that you avoid typedefing structures merely to reduce keystrokes. The extra keystrokes would only be saved in declarations and function prototypes (and maybe if you need to cast something), since you don't need the struct keyword elsewhere; the advantage is that when you see struct FluxCapacitor, you know exactly what it is. If you only see FluxCapacitor alone, you don't know if it is a typedef for a struct, or a union, or an integer type or what.
Note that the posted code was missing the semicolon at the end of the declaration. Also, it is unclear why you have unsigned char* c_string;. This may not allow assignment to a string literal. I have changed this in the code below. You can create a single struct like this:
struct FluxCapacitor
{
char *c_string;
unsigned int value;
};
...
struct FluxCapacitor fcap_1;
You can then assign values to the fields of fcap_1:
fcap_1.c_string = "McFly";
fcap_1.value = 42;
Note that you could also use designated initializers at the point of declaration:
struct FluxCapacitor fcap_2 = { .c_string = "Biff",
.value = 1985
};
If you need an array of FluxCapacitor structures, just declare one:
struct FluxCapacitor fcaps[2];
You can assign to the fields of each array member in a loop:
struct FluxCapacitor fcaps[2];
char *somestrings[] = { "McFly", "Biff" };
unsigned somevalues[] = { 42, 1985 };
for (size_t i = 0; i < 2; i++) {
fcaps[i].c_string = somestrings[i];
fcaps[i].value = somevalues[i];
}
Alternatively, you can use designated initializers here too:
struct FluxCapacitor fcaps[2] = { { .c_string = "McFly", .value = 42 },
{ .c_string = "Biff", .value = 1985}
};
Using malloc()
Since OP seems determined to use malloc(), it would be good to first recall that memory allocated with malloc() must later be deallocated with free(). Also note that malloc() can fail to allocate memory, returning a null pointer. Thus the result of a call to malloc() must be checked before attempting to dereference this pointer. The additional complexity should be avoided in favor of the above approaches unless OP has good reason to do manual allocation.
In the code below, the function create_flux_cap() takes a string and an unsigned int as arguments, and returns a pointer to a newly allocated FluxCapacitor structure with the arguments assigned to the appropriate fields. Note that since the FluxCapacitor structure is accessed through a pointer, the arrow operator is used instead of the dot operator.
Inside the function, the return value from the call to malloc() is checked before attempting assignment. If the allocation has failed, no assignment is made and a null pointer is returned to the calling function. Note that in the call to malloc(), the result is not cast, since there is no need for this in C and it needlessly clutters the code. Also observe that an identifier is used instead of an explicit type with the sizeof operator. This is less error-prone, easier to maintain if types change in the future, and is much cleaner code. That is, instead of this:
new_fcap = (struct FluxCapacitor *)malloc(sizeof (struct FluxCapacitor));
use this:
new_fcap = malloc(sizeof *new_fcap);
In main(), the return values from the calls to create_flux_cap() are checked. If an allocation has failed, the program exits with an error message.
The stdlib.h header file has been included for the function prototypes of malloc() and exit(), and also for the macro EXIT_FAILURE.
#include <stdio.h>
#include <stdlib.h>
struct FluxCapacitor
{
char* c_string;
unsigned value;
};
struct FluxCapacitor * create_flux_cap(char *, unsigned);
int main(void)
{
struct FluxCapacitor *fcap_1 = create_flux_cap("McFly", 42);
struct FluxCapacitor *fcap_2 = create_flux_cap("Biff", 1985);
/* Check for allocation errors */
if (fcap_1 == NULL || fcap_2 == NULL) {
fprintf(stderr, "Unable to create FluxCapacitor\n");
exit(EXIT_FAILURE);
}
/* Display contents of structures */
printf("%s, %u\n", fcap_1->c_string, fcap_1->value);
printf("%s, %u\n", fcap_2->c_string, fcap_2->value);
/* Free allocated memory */
free(fcap_1);
free(fcap_2);
return 0;
}
struct FluxCapacitor * create_flux_cap(char *str, unsigned val)
{
struct FluxCapacitor *new_fcap;
new_fcap = malloc(sizeof *new_fcap);
if (new_fcap != NULL) {
new_fcap->c_string = str;
new_fcap->value = val;
}
return new_fcap;
}
You need malloc for dynamic allocation of memory.In your case, both the types char and int are known to the compiler, it means the compiler can know the exact memory requirement at compile time.
For e.g. you can create a struct object like in the main function
#include<stdio.h>
#include<stdlib.h>
struct FluxCapacitor{
unsigned char* c_string;
unsigned int value;
};
int main() {
FluxCapacitor x;
x.c_string = "This is x capacitor"
x.value = 10
}
The x is of value type. You can make a copy and pass around this value. Also, observe we are using . notation to access its member variables.
But this doesn't happen at all time. We are not aware of future FluxCapacitor requirement and so above program will need more memory as while it is running and by using the malloc we can ask the compiler to provide us requested memory. This is a good place to use malloc, what malloc does is, it returns us a pointer to a piece of memory of the requested size. It is dynamic memory allocation.
Here's a simple example: let suppose if you need struct declaration of FluxCapacitor but don't know how many you will need, then use malloc
#include<stdio.h>
#include<stdlib.h>
typedef struct FluxCapacitor {
unsigned char* c_string;
int value;;
} flux;
// typedef is used to have the alias for the struct FluxCapacitor as flux
int main() {
flux *a = malloc(sizeof(flux)); // piece of memory requested
a -> c_string = "Hello World"; // Pointer notation
a -> value = 5;
free(a); // you need to handle freeing of memory
return 0;
}
.
struct first_struct
{
int a;
int b;
};
struct second_struct
{
char d;
int e;
};
struct second_struct second_ins = {'a',10};
struct first_struct first_ins = {20,12};
int main()
{
struct second_struct *pointer = &first_ins;
printf("%d\n",pointer->d);
return 0;
}
And I get an output of 20. Basically, I was trying to see that if I declare a structure pointer, and try to point this to an instance of another structure, what result do I get. Besides a warning from compiler for an incompatible pointer type, it builds and runs fine.
I was trying to understand how this operation was interpreted by compiler. Shouldnt this be undefined, or may be it is and I am just getting lucky with the result.
It's likely that both structs have the same element-wise alignment: sizeof(first_struct) == sizeof(second_struct) and: int e starts at the same offset in the struct as: int b
In other words, char d is effectively stored as an int in terms of layout. It's simply a lucky coincidence on your platform, and will not work portably.
#include <stdlib.h>
struct timer_list
{
};
int main(int argc, char *argv[])
{
struct foo *t = (struct foo*) malloc(sizeof(struct timer_list));
free(t);
return 0;
}
Why the above segment of code compiles (in gcc) and works without problem while I have not defined the foo struct?
because in your code snippet above, the compiler doesn't need to know the size of struct foo, just the size of a pointer to struct foo, which is independent of the actual definition of the structure.
Now, if you had written:
struct foo *t = malloc(sizeof(struct foo));
That would be a different story, since now the compiler needs to know how much memory to allocate.
Additionally, if you at an point you try to access a member of a struct foo* (or dereference a pointer to a foo):
((struct foo*)t)->x = 3;
The compiler would also complain, since at this point it needs to know the offset into the structure of x.
As an aside, this property is useful to implement an Opaque Pointer.
"And what about free(t)? Can the compiler free the memory without knowing the real size of the struct?"
No, compiler doesn't free anything. Free() is just a function with input parameter void *.