开发者

C - sizeof() on static char arrays inside a struct - impossible?

开发者 https://www.devze.com 2023-03-22 23:24 出处:网络
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 ch

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") } },
};
0

精彩评论

暂无评论...
验证码 换一张
取 消