我在C中有一个大数组(如果有所不同,则不是C++).我想将所有成员初始化为相同的值.我发誓我曾经知道一个简单的方法来做到这一点.我可以memset()
在我的情况下使用,但是没有办法在C语法中构建这样做吗?
除非该值为0(在这种情况下,您可以省略初始化程序的某些部分,并且相应的元素将初始化为0),否则没有简单的方法.
但是,不要忽视明显的解决方案:
int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
缺少值的元素将初始化为0:
int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...
所以这会将所有元素初始化为0:
int myArray[10] = { 0 }; // all elements 0
在C++中,空的初始化列表也会将每个元素初始化为0. C 不允许这样做:
int myArray[10] = {}; // all elements 0 in C++
请记住,如果未指定初始化程序,具有静态存储持续时间的对象将初始化为0:
static int myArray[10]; // all elements 0
而"0"并不一定意味着"所有位为零",因此使用上述内容比memset()更好,更便携.(浮点值将初始化为+0,指向空值的指针等)
如果您的编译器是GCC,您可以使用以下语法:
int array[1024] = {[0 ... 1023] = 5};
查看详细说明:http: //gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html
要静态初始化具有相同值的大型数组,而不使用多个复制粘贴,您可以使用宏:
#define VAL_1X 42 #define VAL_2X VAL_1X, VAL_1X #define VAL_4X VAL_2X, VAL_2X #define VAL_8X VAL_4X, VAL_4X #define VAL_16X VAL_8X, VAL_8X #define VAL_32X VAL_16X, VAL_16X #define VAL_64X VAL_32X, VAL_32X int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };
如果您需要更改该值,则必须仅在一个地方进行更换.
(Jonathan Leffler提供)
您可以通过以下方式轻松概括:
#define VAL_1(X) X #define VAL_2(X) VAL_1(X), VAL_1(X) /* etc. */
可以使用以下方法创建变体:
#define STRUCTVAL_1(...) { __VA_ARGS__ } #define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__) /*etc */
适用于结构或复合数组.
#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__) struct Pair { char key[16]; char val[32]; }; struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") }; int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };
宏名称可以协商.
如果要确保显式初始化数组的每个成员,只需省略声明中的维:
int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
编译器将从初始化列表中推断出维度.不幸的是,对于多维数组,只能省略最外层的维度:
int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
没关系,但是
int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
不是.
我看到一些使用这种语法的代码:
char* array[] = { [0] = "Hello", [1] = "World" };
如果您正在创建一个使用枚举作为索引的数组,它变得特别有用:
enum { ERR_OK, ERR_FAIL, ERR_MEMORY }; #define _ITEM(x) [x] = #x char* array[] = { _ITEM(ERR_OK), _ITEM(ERR_FAIL), _ITEM(ERR_MEMORY) };
这样可以使事情保持正常,即使您碰巧无序地编写了一些枚举值.
关于这种技术的更多信息可以在这里和这里找到.
int i; for (i = 0; i < ARRAY_SIZE; ++i) { myArray[i] = VALUE; }
我认为这比
int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
加入数组大小的变化.
你可以像上面详细描述的那样完成整个静态初始化器的事情,但是当你的数组大小改变时(当你的数组嵌入时,如果你没有添加适当的额外初始化器你得到垃圾),它可能是一个真正的无赖.
memset为您的工作提供了运行时命中,但没有正确执行的代码大小不受阵列大小更改的影响.几乎在所有情况下,当数组大于几十个元素时,我会使用此解决方案.
如果静态声明数组非常重要,我会编写一个程序来为我编写程序并使其成为构建过程的一部分.
这是另一种方式:
static void unhandled_interrupt(struct trap_frame *frame, int irq, void *arg) { //this code intentionally left blank } static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = { [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL}, };
看到:
C-扩展
指定的内容
然后问一个问题:什么时候可以使用C扩展?
上面的代码示例位于嵌入式系统中,永远不会看到来自其他编译器的光.
对于初始化'普通'数据类型(如int数组),您可以使用括号表示法,但如果数组中仍有空格,它将在最后一个之后将值归零:
// put values 1-8, then two zeroes int list[10] = {1,2,3,4,5,6,7,8};
一个略微诙谐的答案; 写下声明
array = initial_value
用您最喜欢的支持数组的语言(我的是Fortran,但还有很多其他语言),并将其链接到您的C代码.你可能想把它包装成一个外部函数.
如果数组恰好是int或任何具有int大小的东西,或者您的mem-pattern的大小适合于int的精确时间(即全零或0xA5A5A5A5),则最好的方法是使用memset()。
否则,在循环中调用memcpy()来移动索引。