在结构中的静态字符数组上的C-sizeof()-不可能?

在结构中的静态字符数组上的C-sizeof()-不可能?,c,arrays,struct,sizeof,C,Arrays,Struct,Sizeof,我需要为每个数组元素存储两个项目-两个char数组,可能包含空字节-然后仍然能够使用sizeof()获取它们的长度。由于这些值在执行期间不会改变,我认为GCC应该能够处理这个问题 代码如下: #include <stdlib.h> #include <stdio.h> struct name_data { char *name; char *data; } name_bins [] = { { "John", "\xAA\xAA\x00\xAA"

我需要为每个数组元素存储两个项目-两个
char
数组,可能包含空字节-然后仍然能够使用
sizeof()
获取它们的长度。由于这些值在执行期间不会改变,我认为GCC应该能够处理这个问题

代码如下:

#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(bin_test));
    printf("sizeof(name_bins[1].data) = %lu\n", sizeof(name_bins[1].data));
    exit(0);
}
但是,
bin\u test
相当于
name\u bin[1]。内容中的数据
虽然类型定义不同-
bin\u test
是一个
char[]
names\u bin[1]。数据
是一个
char*

有没有办法用
char[]
s来定义
name\u bin
数组?
有没有办法强迫GCC将这些值识别为静态常量,并使用
sizeof()
-返回它在编译时已经计算过的实际内容大小?

不,这是不可能的。
struct
的大小是恒定的(
sizeof
anyobject
name\u data
总是相同的)。如果可能的话,您可以拥有两个相同类型、不同大小的对象。

不,这是不可能的。
struct
的大小是恒定的(
sizeof
anyobject
name\u data
总是相同的)。如果可能的话,您可以有两个相同类型、大小不同的对象。

如果您仔细考虑一下您在这里要求编译器做什么,您可能会意识到您所要求的是不现实的

为了让编译器计算出
sizeof(name_bins[1].data)
11
,它必须确保指向包含
sizeof
的代码行的所有可能路径在到达
name_bins[1].data时都具有完全相同的状态

在您给出的简单示例中,您可能希望编译器能够以某种方式理解这一点。但是,如果您的应用程序变得更复杂怎么办?编译器如何知道
name\u bins[1]。数据
仍然包含
“\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05”

编辑:根据注释,可以创建包含数据和大小的新类型:

typedef struct ConstByteString {
    const unsigned char* data;
    size_t length;
} ConstByteString;
然后使用:

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

如果您仔细考虑一下您在这里要求编译器做什么,您可能会意识到您所要求的是不现实的

为了让编译器计算出
sizeof(name_bins[1].data)
11
,它必须确保指向包含
sizeof
的代码行的所有可能路径在到达
name_bins[1].data时都具有完全相同的状态

在您给出的简单示例中,您可能希望编译器能够以某种方式理解这一点。但是,如果您的应用程序变得更复杂怎么办?编译器如何知道
name\u bins[1]。数据
仍然包含
“\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05”

编辑:根据注释,可以创建包含数据和大小的新类型:

typedef struct ConstByteString {
    const unsigned char* data;
    size_t length;
} ConstByteString;
然后使用:

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

通过将
数据的大小存储为一个单独的条目,您几乎可以随心所欲:

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")
     }
};
然后:

printf("sizeof(bin_test) = %lu\n", sizeof(bin_test));
printf("sizeof(name_bins[1].data) = %lu\n", (unsigned long)name_bins[1].data_size);
然后,您只需确保您的
name\u bin
初始化是正确的。您可以在混合中加入宏,以避免重复:

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

通过将
数据的大小存储为一个单独的条目,您几乎可以随心所欲:

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")
     }
};
然后:

printf("sizeof(bin_test) = %lu\n", sizeof(bin_test));
printf("sizeof(name_bins[1].data) = %lu\n", (unsigned long)name_bins[1].data_size);
然后,您只需确保您的
name\u bin
初始化是正确的。您可以在混合中加入宏,以避免重复:

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

谢谢Sander——我确实明白你的意思,我在想也许有一种方法可以告诉GCC这个变量是不可触及的(不能在整个执行流程中改变)——然后,sizeof应该成为可能。有什么办法可以做到这一点吗?@Arkadi:简言之:没有。
data
是一个
char*
,然后
sizeof(name\u bins[1]。data)
将与
sizeof(char*)
相同。或者
data
是一个字符数组
char
,然后
sizeof(name\u bins[1].data)
将返回该数组的总大小(但是
sizeof(name\u bins[i].data)
对于每个
i
都是相同的)。为什么需要这个来处理
sizeof
?因为我不能使用strlen(),因为它可能包含空字节。有没有一种方法可以将结构定义为包含2个字符[]而不是2个字符*,从而允许sizeof()工作?(我没能做到这一点)@Arkadi:为什么不将数据的大小存储在struct中呢?或者更好的是,创建自己的新类型来抽象该细节(我将在答案中添加一个示例)。感谢Sander,这与mu的答案非常相似-感谢您的帮助!谢谢Sander——我确实明白你的意思,我在想也许有一种方法可以告诉GCC这个变量是不可触及的(不能在整个执行流程中改变)——然后,sizeof应该成为可能。有什么办法可以做到这一点吗?@Arkadi:简言之:没有。
data
是一个
char*
,然后
sizeof(name\u bins[1]。data)
将与
sizeof(char*)
相同。或者
data
是一个字符数组
char
,然后
sizeof(name\u bins[1].data)
将返回该数组的总大小(但是
sizeof(name\u bins[i].data)
对于每个
i
都是相同的)。为什么需要这个来处理
sizeof
?因为我不能使用strlen(),因为它可能包含空字节。有没有一种方法可以将结构定义为包含2个字符[]而不是2个字符*,从而允许sizeof()工作?(我没能做到这一点)@Arkadi:为什么不将数据的大小存储在struct中呢?或者更好的是,创建自己的新类型来抽象这个细节