C 动态数组和预构建数据
在C中,我尝试执行以下操作:C 动态数组和预构建数据,c,arrays,static,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' } }
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 */
};
总之,我想要一个类型string\u t
,它以另一个类型wchararray\u t
结尾,该类型本身是动态大小的——它的大小存储在length
中。此外,我还想编写一个预构建的特定字符串,作为静态数据,在这里s1
长度为5
以上代码假定C99支持/*1*/
。据我所知,甚至C99标准都不支持将下部结构包含在/*2*/
的更大结构中,但GCC接受它。然而,在/*3*/
GCC放弃:
error: initialization of flexible array member in a nested context
作为一种变通方法,到目前为止,上述理想代码被编写为以下hack,即“工作类型”:
…我们将使用“s1.b”作为预构建字符串(并且永远不要引用“s1.a”,它在这里仅用于s1的静态声明)。然而,它突破了最新的GCC4.8,它优化了我们的部分代码,因为很明显,wchararray\u t
的项上的任何循环都只能迭代一次,因为它是一个长度为1的数组
通过向gcc提供选项-fno adgressive loop optimizations
,可以解决这个特殊问题。也可以通过不在wchararray\u t
的items[]
数组中声明长度来修复它,使其成为动态数组“仅仅因为”。然而,这种编写代码的方法是一种非常糟糕的方法,我更喜欢一种完全不同的方法来解决这个问题
(请注意,所有这些都是PyPy生成的C代码,而不是手工编写的代码;只要不阻止“有效”的C优化,任何更改都可以,包括是否需要更改我们在任何地方访问数据的方式。)
编辑:将“char[]”替换为“int[]”,它不接受双引号语法“hello”
。这是因为我正在为任何数组类型寻找解决方案
未解决:谢谢大家的建议。似乎没有干净的方法,所以我实现了一个骇人的解决方案:声明类型k+1次,一次使用灵活的数组“int items[];”,另一次使用“int items[N];”来声明所需的各种N值。这需要一些额外的技巧:例如,不为MSVC使用灵活的数组(它们在那里的工作方式不同;我没有调查是否完全相同的语法可以工作);GCC遵循C99的说法,对包含int项[]的结构不满意代码>作为唯一字段。但是,如果我们添加一个虚拟字段char\u dummy[0],它会很高兴代码>。。。据我所知,这并不是严格意义上的C99…我假设有一些理由将字符串保留在结构中,并且您希望通过不使用C字符串初始化来保存字符
但是,如果没有,您可以:
typedef struct {
int length;
char *items; /* 1 */
} chararray_t;
typedef struct {
long hash;
chararray_t chars; /* 2 */
} string_t;
static string_t s1 = {
617862378,
{ 5, "Hell" } /* 3 */
};
s1.chars.items[4] = 'o' ;
看起来你可以做工会的把戏,但是改用打字
#include <stdio.h>
typedef struct { int length; int items[]; } 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; } s5 = {
617862378,
{ 5, { 'H', 'e', 'l', 'l', 'o' } }
};
string_t *s1 = (string_t*) &s5 ;
int main( int argc, char *argv[])
{
for( int i = 0 ; i < s1->chars.length ; i++ )
{
printf ( "%c", s1->chars.items[i] );
}
printf( "\n" );
}
#包括
typedef结构{int length;int items[];}wchararray\u t;
typedef结构{long hash;wchararray\u t chars;}string\u t;
typedef结构{int length;int items[5];}wchararray\u len5\u t;
typedef结构{long hash;wchararray_len5_t chars;}string_len5_t;
静态并集{string_len5_t a;string_t b;}s5={
617862378,
{5,{H',e',l',l',o'}
};
字符串s1=(字符串)和s5;
int main(int argc,char*argv[])
{
对于(int i=0;ichars.length;i++)
{
printf(“%c”,s1->chars.items[i]);
}
printf(“\n”);
}
#包括
类型定义结构{
整数长度;
字符项[];/*1*/
}查拉雷;
类型定义结构{
长散列;
chararray\u t chars;/*2*/
}弦乐;
/*静态字符串\u t s1={
617862378,
{5,{H',e',l',l',o'}//3
};*/
静态字符串s1=
{
617862378,
{6,“你好”}/*3*/
};
int main()
{
printf(“%d%d%s\n”,s1.hash,s1.chars.length,s1.chars.items);
返回0;
}
为空字符添加1,et voila!:)
编辑,也适用于2级嵌套(GCC 4.8.0)
#包括
类型定义结构{
整数长度;
字符项[];/*1*/
}查拉雷;
类型定义结构{
长散列;
chararray\u t chars;/*2*/
}弦乐;
类型定义结构{
长数;
字符串到达;
}实验;
静态实验1=
{
617862378,
{786,{6,“你好”}/*3*/
};
int main()
{
printf(“%d%d%d%s\n”,s1.number,s1.arr.hash,s1.arr.chars.length,s1.arr.chars.items);
返回0;
}
----------编辑2------------------
找到了绕过限制的方法
最终代码::
#include <stdio.h>
typedef struct {
int length;
int *items; /* 1 */
} intarray_t;
typedef struct {
long hash;
intarray_t chars; /* 2 */
int dummy[2];
} string_t;
/*string_t s1 =
{
617862378,
{
6,
{1,2,3,4,5,6}
},
{
0,0
}
};*/
string_t s1 = {617862378,{},{0,0}};
int main()
{
int i=0;
intarray_t t1 = {.length = 6, .items = (int[6]){1,2,3,4,5,6}};
s1.chars = t1;
printf("%d %d\n",s1.hash,s1.chars.length);
while(i<s1.chars.length)
{
printf("%d",s1.chars.items[i]);
i++;
}
putchar('\n');
return 0;
}
#包括
类型定义结构{
整数长度;
int*项;/*1*/
}无阵列;
类型定义结构{
长散列;
无阵列字符;/*2*/
int-dummy[2];
}弦乐;
/*字符串s1=
{
617862378,
{
6.
{1,2,3,4,5,6}
},
{
0,0
}
};*/
字符串s1={617862378,{},{0,0};
int main()
{
int i=0;
intarray_t t1={.length=6,.items=(int[6]){1,2,3,4,5,6};
s1.chars=t1;
printf(“%d%d\n”,s1.hash,s1.chars.length);
虽然(我这很粗糙,但这行得通吗
#include <stdio.h>
typedef struct {
int length;
int items[]; /* 1 */
} wchararray_t;
typedef struct {
long hash;
wchararray_t chars; /* 2 */
int dummy[]; /* hack here */
} string_t;
static string_t s1 = {
617862378, { 5 },
{ 'H', 'e', 'l', 'l', 'o' } /* 3: changed assignment */
};
int main(void)
{
int i;
for (i=0; i < 5; ++i) {
putchar(s1.chars.items[i]);
}
putchar('\n');
return 0;
}
但它似乎奏效了
编辑:添加一个“填充成员”来确保items[]
始终正确对齐如何
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
/* change to the strictest alignment type */
typedef long aligner;
typedef struct {
long stuff; /* to show misalignment on 64-bit */
int length;
aligner padding;
int items[];
} chararray_t;
typedef struct {
long hash;
chararray_t chars;
int dummy[];
} string_t;
static string_t b1 = {
617862378,
{ 42, 5 },
{-1, -2, -3, -4, -5}
};
int main(void)
{
int i;
printf("sizeof chararray_t: %zu\n", sizeof(chararray_t));
printf("offsetof items: %zu\n", offsetof(chararray_t, items));
printf("sizeof string_t: %zu\n", sizeof(string_t));
printf("offsetof dummy: %zu\n", offsetof(string_t, dummy));
for (i=0; i < 5; ++i) {
printf("%d ", b1.chars.items[i]);
}
putchar('\n');
for (i=0; i < 5; ++i) {
printf("%d ", b1.dummy[i]);
}
putchar('\n');
return 0;
}
回答我自己的问题并将其写下来。另一种黑客方法是在Alok建议的基础上进行构建,该建议可能会偶尔给出虚假的对齐方式,然后通过初始化时间代码修复对齐方式。这假设程序中使用的绝大多数此类类型恰好正确对齐。代码:
typedef struct {
long stuff; /* to show misalignment on 64-bit */
int length;
int items[];
} chararray_t;
typedef struct {
long hash;
chararray_t chars;
int dummy[];
} string_t;
static string_t b1 = {
617862378,
{ 42, 5 },
{-1, -2, -3, -4, -5}
};
/* same with b2 .. b6 */
void fixme(void) {
/* often compares as equal, and the whole function is removed */
if (offsetof(string_t, dummy) !=
offsetof(string_t, chars) + offsetof(chararray_t, items)) {
static string_t *p_array[] = { &b1, &b2, &b3, &b4, &b5, &b6 };
string_t *p;
int i;
for (i=0; i<6; i++) {
p = p_array[i];
memmove(p->chars.items, p->dummy, p->chars.length * sizeof(int));
}
}
}
typedef结构{
long stuff;/*显示64位上的未对齐*/
整数长度;
国际项目[];
}查拉雷;
类型定义结构{
长散列;
chararray_t chars;
int-dummy[];
}弦乐;
静态字符串\u t b1={
617862378,
{ 42, 5 },
{-1, -2, -3, -4, -5}
};
/*与b2..b6相同*/
void fixme(void){
/*经常
#include <stdio.h>
typedef struct {
int length;
int items[]; /* 1 */
} wchararray_t;
typedef struct {
long hash;
wchararray_t chars; /* 2 */
int dummy[]; /* hack here */
} string_t;
static string_t s1 = {
617862378, { 5 },
{ 'H', 'e', 'l', 'l', 'o' } /* 3: changed assignment */
};
int main(void)
{
int i;
for (i=0; i < 5; ++i) {
putchar(s1.chars.items[i]);
}
putchar('\n');
return 0;
}
xx.c:10:22: warning: invalid use of structure with flexible array member [-pedantic]
xx.c:16:9: warning: initialization of a flexible array member [-pedantic]
xx.c:16:9: warning: (near initialization for ‘s1.dummy’) [-pedantic]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
/* change to the strictest alignment type */
typedef long aligner;
typedef struct {
long stuff; /* to show misalignment on 64-bit */
int length;
aligner padding;
int items[];
} chararray_t;
typedef struct {
long hash;
chararray_t chars;
int dummy[];
} string_t;
static string_t b1 = {
617862378,
{ 42, 5 },
{-1, -2, -3, -4, -5}
};
int main(void)
{
int i;
printf("sizeof chararray_t: %zu\n", sizeof(chararray_t));
printf("offsetof items: %zu\n", offsetof(chararray_t, items));
printf("sizeof string_t: %zu\n", sizeof(string_t));
printf("offsetof dummy: %zu\n", offsetof(string_t, dummy));
for (i=0; i < 5; ++i) {
printf("%d ", b1.chars.items[i]);
}
putchar('\n');
for (i=0; i < 5; ++i) {
printf("%d ", b1.dummy[i]);
}
putchar('\n');
return 0;
}
sizeof chararray_t: 24
offsetof items: 24
sizeof string_t: 32
offsetof dummy: 32
-1 -2 -3 -4 -5
-1 -2 -3 -4 -5
typedef struct {
long stuff; /* to show misalignment on 64-bit */
int length;
int items[];
} chararray_t;
typedef struct {
long hash;
chararray_t chars;
int dummy[];
} string_t;
static string_t b1 = {
617862378,
{ 42, 5 },
{-1, -2, -3, -4, -5}
};
/* same with b2 .. b6 */
void fixme(void) {
/* often compares as equal, and the whole function is removed */
if (offsetof(string_t, dummy) !=
offsetof(string_t, chars) + offsetof(chararray_t, items)) {
static string_t *p_array[] = { &b1, &b2, &b3, &b4, &b5, &b6 };
string_t *p;
int i;
for (i=0; i<6; i++) {
p = p_array[i];
memmove(p->chars.items, p->dummy, p->chars.length * sizeof(int));
}
}
}