5

我刚刚在 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++ 编译器(尽管不情愿地)接受这段代码?

4

3 回答 3

4

是什么让您认为它无法在 C 中编译?

C++: http: //ideone.com/KLPh4 C:http: //ideone.com/VYUbL

注意你的警告。 我怎么强调都不过分。警告可以帮助您发现此类错误。

好吧,C 中的错误消息非常清楚地表明了区别:C 要求初始化器是常量,而不是任意表达式。为什么这些不被视为常量对我来说毫无意义,因为这在 C 中编译得很好:

于 2012-07-19T16:19:57.147 回答
4

为了回答您的问题,我将首先回答:为什么这无法在 C 中编译?好吧,它无法编译,原因是:

initializer element is not constant

为了更好的衡量,让我们{}从 C 中删除 s:

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},
};
于 2012-07-19T16:36:57.913 回答
3

C++ 有一个逗号运算符,它计算其两个操作数并返回其右操作数的值,而忽略其左操作数。你可以在这里更清楚地看到它。

还有 C,显然 =)(谢谢,@BenVoigt)

于 2012-07-19T16:19:12.643 回答