动态数组和预建数据

Arm*_*igo 25 c arrays static

在C中,我尝试执行以下操作:

typedef struct {
    int length;
    int items[];     /* 1 */
} wchararray_t;

typedef struct {
    long hash;
    wchararray_t chars;   /* 2 */
} string_t;

static string_t s1 = {
    617862378,
    { 5, { 'H', 'e', 'l', 'l', 'o' } }  /* 3 */
};
Run Code Online (Sandbox Code Playgroud)

总而言之,我希望一种类型string_t以另一种类型结束,该类型wchararray_t本身是动态大小的 - 其大小存储在其中length.此外,我还想写一个预建的特殊字符串,作为静态数据,这里s1长度为5.

上面的代码假定C99支持/* 1 */./* 2 */据我所知,将子结构包含在更大的结构中,即使是C99标准也不支持 - 但GCC接受它.然而,在/* 3 */GCC放弃:

error: initialization of flexible array member in a nested context
Run Code Online (Sandbox Code Playgroud)

作为一种解决方法,上面的理想代码到目前为止被写为以下hack,"有点工作":

typedef struct { int length; int items[1]; } wchararray_t;
typedef struct { long hash; wchararray_t chars; } string_t;

typedef struct { int length; int items[5]; } wchararray_len5_t;
typedef struct { long hash; wchararray_len5_t chars; } string_len5_t;

static union { string_len5_t a; string_t b; } s1 = {
    617862378,
    { 5, { 'H', 'e', 'l', 'l', 'o' } }
};
Run Code Online (Sandbox Code Playgroud)

...并且我们使用"s1.b"作为预构建的string_t(并且从不引用"s1.a",这里仅用于s1的静态声明).然而,它打破在最新GCC 4.8,这是因为可优化远的我们的代码部分-显然-任何环路在所述items的一个wchararray_t可以迭代只有一次,因为它是一个长度为1的阵列.

通过给gcc选项来解决这个特殊问题-fno-aggressive-loop-optimizations.它可以或许也没有宣布的长度是固定wchararray_titems[]排列,使之成为一个动态数组'只是因为’.但是,这种编写代码的方式是一种黑客攻击,我更倾向于以完全不同的方式来解决问题...

(请注意,它是由PyPy生成的所有生成的C代码,而不是手写代码;任何更改都很好,包括它是否需要更改我们在任何地方访问数据的方式,只要"有效"C优化不是防止.)

编辑:用"int []"替换"char []",它不接受双引号语法"hello".这是因为我正在寻找任何阵列类型的解决方案.

不解决:感谢大家的建议.似乎没有干净的方法,所以我实现了hackish解决方案:声明类型k + 1次,一次使用灵活的数组"int items [];" 和其他时间用"int items [N];" 对于所需的各种N值.这需要一些额外的黑客攻击:例如,不使用MSVC的灵活数组(它们的工作方式不同;我没有调查,知道完全相同的语法是否有效); 和GCC遵循C99所说的,并且int items[];对仅包含字段的结构不满意.然而,如果我们添加一个虚拟字段char _dummy[0];... 我很高兴...据我所知,这不是严格的C99 ...

Alo*_*hal 2

这有点骇人听闻,但这行得通吗?

\n\n
#include <stdio.h>\n\ntypedef struct {\n    int length;\n    int items[];     /* 1 */\n} wchararray_t;\n\ntypedef struct {\n    long hash;\n    wchararray_t chars;   /* 2 */\n    int dummy[]; /* hack here */\n} string_t;\n\nstatic string_t s1 = {\n    617862378, { 5 },\n    { \'H\', \'e\', \'l\', \'l\', \'o\' }  /* 3: changed assignment */\n};\n\nint main(void)\n{\n    int i;\n    for (i=0; i < 5; ++i) {\n        putchar(s1.chars.items[i]);\n    }\n    putchar(\'\\n\');\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

GCC 给我警告:

\n\n
xx.c:10:22: warning: invalid use of structure with flexible array member [-pedantic]\nxx.c:16:9: warning: initialization of a flexible array member [-pedantic]\nxx.c:16:9: warning: (near initialization for \xe2\x80\x98s1.dummy\xe2\x80\x99) [-pedantic]\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这似乎有效。

\n\n

参考

\n\n

编辑:添加一个“填充成员”以确保items[]始终正确对齐怎么样?

\n\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stddef.h>\n\n/* change to the strictest alignment type */\ntypedef long aligner;\n\ntypedef struct {\n    long stuff;   /* to show misalignment on 64-bit */\n    int length;\n    aligner padding;\n    int items[];\n} chararray_t;\n\ntypedef struct {\n    long hash;\n    chararray_t chars;\n    int dummy[];\n} string_t;\n\nstatic string_t b1 = {\n    617862378,\n    { 42, 5 },\n    {-1, -2, -3, -4, -5}\n};\n\nint main(void)\n{\n    int i;\n\n    printf("sizeof chararray_t: %zu\\n", sizeof(chararray_t));\n    printf("offsetof items: %zu\\n", offsetof(chararray_t, items));\n\n    printf("sizeof string_t: %zu\\n", sizeof(string_t));\n    printf("offsetof dummy: %zu\\n", offsetof(string_t, dummy));\n\n    for (i=0; i < 5; ++i) {\n        printf("%d ", b1.chars.items[i]);\n    }\n    putchar(\'\\n\');\n    for (i=0; i < 5; ++i) {\n        printf("%d ", b1.dummy[i]);\n    }\n    putchar(\'\\n\');\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当我运行上面的代码时,我似乎得到了正确的答案:

\n\n
sizeof chararray_t: 24\noffsetof items: 24\nsizeof string_t: 32\noffsetof dummy: 32\n-1 -2 -3 -4 -5 \n-1 -2 -3 -4 -5 \n
Run Code Online (Sandbox Code Playgroud)\n