C:声明后初始化struct变量

我最近遇到过这个,但无法弄清楚为什么语言允许b = c; 低于和失败b = {3,4}。 允许后者有问题吗?

struct T { int x; int y; }; int main() { T a = {1, 2}; T b; b = {3, 4}; // why does this fail ? T c = {3, 4}; b = c; // this works return 0; } 

它失败是因为{3, 4} ,虽然它是一个有效的初始化器,但它不是一个表达式(至少它不在C中;有关C ++的更多信息,请参见下文)。

C中的每个表达式都有一个可以通过检查表达式本身来确定的类型。 {3, 4}可能是struct Tint[2] (数组类型)或任何其他类型的任何类型。

C99添加了一个名为复合文字的新function,它使用与初始化程序类似的语法,但是让您指定类型,创建表达式:

 b = (struct T){3, 4}; 

注意(struct T) 不是强制转换运算符; 它是复合文字语法的一部分。

有关复合文字的更多信息,请参阅C11标准草案的第6.5.2.5节。

复合文字由1999 ISO C标准(C99)引入。 如果您的编译器不支持C99或更好(* cough * Microsoft * cough *),那么您将无法使用它们。

如果你正在使用C ++(不要忘记,它是一种不同的语言),它不支持复合文字,但可能有另一种选择。 正如Potatoswatter在评论中指出的那样:

 b = T{3, 4}; 

在C ++ 11中有效(但在早期版本的C ++语言中没有)。 这将在C ++标准的5.2.3 [expr.type.conf]部分中介绍。

就此而言,这个:

 b = {3, 4}; 

也是有效的C ++ 11语法。 此表单可用于许多指定的上下文,包括赋值的右侧。 这将在C ++标准的8.5.4 [dcl.init.list]部分中介绍。

最近的C ++标准草案是N3485。

(g ++在C ++中支持C99风格的复合文字作为扩展。)

如果你坚持使用前C99编译器,你总是可以编写自己的初始化函数,例如:

 struct T init_T(int x, int y) { struct T result; result.x = x; result.y = y; return result; } /* ... */ struct T obj; /* ... */ obj = init_T(3, 4); 

这是一项烦人的额外工作(这就是C99添加复合文字的原因),但它确实起到了作用。 另一方面,在大多数情况下,您最好使用初始化:

 struct T obj; /* ... */ { struct T tmp = { 3, 4 }; obj = tmp; } 

哪个更好可能取决于您的计划的结构。

因为您没有使用正确的C99或C11’复合文字’表示法:

 b = (struct T){ 3, 4 }; 

有关更多信息(以及其他地方),请参见§6.5.2 后缀运算符和§6.5.2.5ISO / IEC 9899:2011中的复合文字

( type-name ) { initializer-list }
( type-name ) { initializer-list , }

因为那是语言的定义……我认为除了“编写编译器以允许这样做更难”之外,没有任何特殊原因。

如果你有一个C ++ 11编译器b = T{3, 4}你可以做b = T{3, 4}