I want to understand:
- why it happens that sometimes a
char[1]in C is used aschar*(why doing this?) and - how the internals works (what’s going on)
Giving 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 whenmalloc()ing the struct, to already have some storage for your string without additional allocation. You can sometimes even seechar something[0]used for the same purpose, which makes even less intuitive sense.If something is an array, both its name and
&namejust 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.This line gives the size of space allocated for
a, notbin this struct. Put something afterband used this to subtract. With thepackedattribute (which means you disallow the compiler to mess with alignment, etc.), you should get 1.I get
1.