I want to understand:
char[1]
in C is used as char*
(why doing this?) andGiving following sample program:
#include <stdio.h>
#include <string.h>
struct test_struct {
char *a;
char b[1];
} __attribute__((packed)); ;
int main() {
char *testp;
struct test_struct test_s;
testp = NULL;
memset(&test_s, 0, sizeof(struct test_struct));
printf("sizeof(test_struct) is: %lx\n", sizeof(struct test_struct));
printf("testp at: %p\n", &testp);
printf("testp is: %p\n", testp);
printf("test_s.a at: %p\n", &test_s.a);
printf("test_s.a is: %p\n", test_s.a);
printf("test_s.b at: %p\n", &test_s.b);
printf("test_s.b is: %p\n", test_s.b);
printf("sizeof(test_s.b): %lx \n", sizeof(test_s.b));
printf("real sizeof(test_s.b): %lx \n", ((void *)(&test_s.b) - (void *)(&test_s.a)) );
return 0;
}
I get the following output (OS X, 64bit):
sizeof(test_struct) is: 9
testp at: 0x7fff62211a98
testp is: 0x0
test_s.a at: 0x7fff62211a88
test_s.a is: 0x0
test_s.b at: 0x7fff62211a90
test_s.b is: 0x7fff62211a90
sizeof(test_s.b): 1
real sizeof(test_s.b): 8
Looking at the memory addresses, one can see that even the struct is 9 bytes large, 16 bytes were allocated which seems to be caused by char b[1]
. But I'm not sure if those extra bytes were allocated due to optimization/mem alignment reasons, or if this has to do with C's internal treatment of char arrays.
A real world example can be seen in <fts.h>
:
`man 3 fts` shows the struct member `fts_name` as:
char *fts_name; /* file name */
while /usr/include/fts.h defines the member as:
char fts_name[1]; /* file name */
In the end, fts_name
can really be used as a pointer to a C-string. For example, printing to stdout with printf("%s", ent->fts_name)
works.
So if a char[1]
is really one byte large, it couldn't be used as a memory pointer on my 64bit machine. On the other hand, treating this as a full blown char *
doesn't work either, as can be seen with the test_s.b is
output above, which should show a NULL pointer then...
Here is an answer that describes the char[1]
trick. Basically, the idea is to allocate more memory when malloc()
ing the struct, to already have some storage for your string without additional allocation. You can sometimes even see char something[0]
used for the same purpose, which makes even less intuitive sense.
On the other hand, treating this as a full blown char * doesn't work either, as can be seen with the test_s.b is output above, which should show a NULL pointer then...
If something is an array, both its name and &name
just give the pointer to the start of the array in C. This works regardless of whether it's a member in a struct, or a free standing variable.
printf("real sizeof(test_s.b): %lx \n", ((void *)(&test_s.b) - (void *)(&test_s.a)) );
This line gives the size of space allocated for a
, not b
in this struct. Put something after b
and used this to subtract. With the packed
attribute (which means you disallow the compiler to mess with alignment, etc.), you should get 1.
#include <stdio.h>
#include <string.h>
struct test_struct {
char *a;
char b[1];
char c;
} __attribute__((packed));
int main() {
struct test_struct s;
printf("%lx\n", ((void*)&s.c) - ((void*)&s.b));
return 0;
}
I get 1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With