C - sizeof() on static char arrays inside a struct - impossible?
I need to store two items per array element — two arrays of char
, which might contain null bytes — and then still be able to use sizeof()
to get their length. Since these values will not change during execution, I think GCC should be able to handle this.
Here's the code:
#include <stdlib.h>
#include <stdio.h>
struct name_data {
char *name;
char *data;
} name_bins [] = {
{ "John", "\xAA\xAA\x00\xAA" },
{ "Mark", "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05" },
};
char bin_test[] = "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05";
int main () {
printf("sizeof(bin_test) = %lu\n", sizeof(b开发者_如何转开发in_test));
printf("sizeof(name_bins[1].data) = %lu\n", sizeof(name_bins[1].data));
exit(0);
}
The output of this code is:
sizeof(bin_test) = 11
sizeof(name_bins[1].data) = 8
However, bin_test
is equivalent to name_bins[1].data
in content — although the type definition is different — bin_test
is a char[]
and names_bins[1].data
is a char*
.
Is there a way to define the name_bins
array with char[]
s instead?
Is there a way to force GCC to recognize this values as static constants and return the real content size with sizeof()
— which it already calculates at compile time?
No, this isn't possible. The size of the struct
is constant (sizeof
any object name_data
is always the same). If it were possible, you could have two objects of the same type, with different sizes.
You can almost do what you want by storing the size of data
as a separate entry:
struct name_data {
char *name;
char *data;
size_t data_size;
} name_bins[] = {
{
"John",
"\xAA\xAA\x00\xAA",
sizeof("\xAA\xAA\x00\xAA")
}, {
"Mark",
"\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05",
sizeof("\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05")
}
};
And then:
printf("sizeof(bin_test) = %lu\n", sizeof(bin_test));
printf("sizeof(name_bins[1].data) = %lu\n", (unsigned long)name_bins[1].data_size);
Then you'd just have to make sure your name_bins
initialization was right. You could toss a macro in the mix to avoid repeating yourself though:
#define BIN(x,y) { (x), (y), sizeof(y) }
struct name_data {
char *name;
char *data;
size_t data_size;
} name_bins [] = {
BIN("John", "\xAA\xAA\x00\xAA"),
BIN("Mark", "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05")
};
If you think for a bit about what you're asking the compiler to do here, you'll probably realize that what you're asking is not realistic.
In order for the compiler to figure out that sizeof(name_bins[1].data)
is 11
, it would have to make sure that every possible path that leads to the line of code containing the sizeof
has the exact same state when it comes to the name_bins[1].data
object.
In the simple example you gave, you might expect the compiler to be able to somehow figure that out. But what if your application becomes more complex ? How will the compiler know that name_bins[1].data
still contains "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05"
?
EDIT : Following up from the comments, you could create a new type that holds both the data and the size :
typedef struct ConstByteString {
const unsigned char* data;
size_t length;
} ConstByteString;
and then use that :
struct name_data {
const char* name;
ConstByteString data;
} name_bins [] = {
{ "John", { "\xAA\xAA\x00\xAA", sizeof("\xAA\xAA\x00\xAA") } },
{ "Mark", { "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05", sizeof("\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05") } },
};
精彩评论