我刚刚在C ++中遇到了一个令人讨厌的错误。所以我有一个寄存器和值列表,它们包含在一个结构中,然后这些结构在一个数组中初始化。但后来我不小心输入了()
而不是{}
。这是一些测试代码:
#include <stdio.h>
struct reg_val {
unsigned reg;
unsigned val;
};
struct reg_val faulty_array[] = {
{0x5001, 0xff},
{0x5580, 0x01},
(0x5580, 0x02), //<- THIS LINE IS THE PROBLEM
(0x5589, 0x00), //<- AND THIS LINE
};
struct reg_val good_array[] = {
{0x5001, 0xff},
{0x5580, 0x01},
{0x5580, 0x02},
{0x5589, 0x00},
};
int main()
{
unsigned i;
unsigned faulty_size = sizeof(faulty_array) / sizeof(struct reg_val);
printf("Size of faulty array: %d\n", faulty_size);
for (i = 0; i < faulty_size; ++i) {
printf("faulty reg: %x val: %x\n", faulty_array[i].reg,
faulty_array[i].val);
}
unsigned good_size = sizeof(good_array) / sizeof(struct reg_val);
printf("\nSize of good array: %d\n", good_size);
for (i = 0; i < good_size; ++i) {
printf("good reg: %x val: %x\n", good_array[i].reg,
good_array[i].val);
}
return 0;
}
我对C更熟悉,令我惊讶的是仍然用g ++编译:
$ g++ -Wall array.cc
array.cc:11: warning: left-hand operand of comma has no effect
array.cc:12: warning: left-hand operand of comma has no effect
array.cc:13: warning: missing braces around initializer for ‘reg_val’
$ ./a.out
Size of faulty array: 3
faulty reg: 5001 val: ff
faulty reg: 5580 val: 1
faulty reg: 2 val: 0 <-- the first value gets discarded as mentioned in the compiler warning
Size of good array: 4
good reg: 5001 val: ff
good reg: 5580 val: 1
good reg: 5580 val: 2
good reg: 5589 val: 0
这段代码显然无法使用C编译器进行编译,C ++的不同之处在于C ++编译器(虽然不情愿地)接受这段代码?
答案 0 :(得分:4)
是什么让你认为它无法在C中编译?
C ++:http://ideone.com/KLPh4 C:http://ideone.com/VYUbL
注意你的警告。我不能强调这一点。警告可以帮助你捕捉到这样的错误。
好吧,C中的错误消息使得差异非常明显:C要求初始化器是常量,而不是任意表达式。对我来说,为什么那些不被认为是常量是没有意义的,因为这在C中编译得很好:
答案 1 :(得分:4)
要回答你的问题,我将首先回答:为什么这不能用C编译?好吧,由于:
,它无法编译initializer element is not constant
为了更好的衡量,让我们从C:
中删除{}
struct reg_val faulty_array[] = {
{0x5001, 0xff},
{0x5580, 0x01},
0x5580, 0x02, //<- THIS LINE IS THE PROBLEM
0x5589, 0x00, //<- AND THIS LINE
};
现在程序输出:
Size of faulty array: 4
faulty reg: 5001 val: ff
faulty reg: 5580 val: 1
faulty reg: 5580 val: 2
faulty reg: 5589 val: 0
C标准(和C ++)完全允许这样做。 C(和C ++)将大括号括起来初始化结构元素(这将会回来)。您的代码在C中失败,因为具有静态存储持续时间的对象必须使用常量表达式或包含常量表达式的聚合初始值设定项进C不会将(0x5580, 0x02)
视为常量表达式。
这个(不幸)在C ++中编译,因为C ++将两个常量表达式之间的逗号运算符视为常量表达式,因此您的代码更像是:
struct reg_val faulty_array[] = {
{0x5001, 0xff},
{0x5580, 0x01},
0x02,
0x00,
};
......当然,这是允许的。
struct reg_val faulty_array[] = {
{0x5001, 0xff},
{0x5580, 0x01},
{0x02, 0x00},
};
答案 2 :(得分:3)
C ++有一个逗号运算符,用于计算其两个操作数并返回其右操作数的值,忽略其左侧。 You can see it more clearly here.
C也是,显然=)(谢谢,@ BenVoigt)