2013-08-20 57 views
22

我最近遇到了这个,但不知道为什么语言会允许b = c;在下面并且失败b = {3,4}。允许后者有问题吗?C:声明后初始化结构体变量

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

我知道这**是**欺骗:http://stackoverflow.com/q/16614045/694576 – alk

+0

@克,这不完全是一个重复。另一个链接讲的是将一个结构赋值给一个结构体,而这个结构体只是将一个初始化程序赋值给一个结构体。 – user1952500

+1

'b = {3,4};'不是一个初始化,而是一个赋值。前者是'T b = {3,4};'。是的,这两个是不同的野兽...... :-)初始化发生在定义过程中。在所有其他情况下,分配都会发生。 – alk

回答

32

它失败,因为{3, 4},尽管它是一个有效的初始化,不是表达式(至少它是不是在C;见以下更多关于C++)。

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

C99增加了一个名为复合文字使用类似的语法来初始化,但让你指定类型的新功能,创建一个表达式:

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

注意,(struct T)铸造操作;它是复合文字语法的一部分。

有关复合文字的更多信息,请参阅draft C11 standard的第6.5.2.5节。

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

如果您使用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; 
} 

哪一个更好可能取决于您的程序的结构。

+3

在C++中,括号中的type-id拉拉符号是非法的,但是'T {3,4}'有诀窍。 – Potatoswatter

+0

有趣。为什么编译器不同地处理初始化和赋值?初始化时,它似乎将RHS解释为一个结构体,而在赋值时它不确定吗? – user1952500

+1

@ user1952500:正如我所说的,这是因为'{3,4}'是一个有效的初始化程序,它从被初始化的对象中获取它的类型,但它不是一个有效的表达式。 –

5

因为你没有使用正确的C99或C11 '复合文字' 符号:

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

见§6.5.2后缀运算符和§6.5.2.5复合文字在ISO/IEC 9899:2011获取更多信息(以及其他地方)。

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

+0

Microsoft C编译器不接受此初始值设定项。 – JackCColeman

+1

@JackCOoleman:正如第一句话所说:这是一个C99“复合文字”。微软仍然实施C89(即从24年前开始)。 – MSalters

+0

@JackCColeman:因为,正如MSalters所说,Microsoft C编译器是C89编译器,因此从C99获知它不支持该功能并不奇怪。事实上,引用标准(旧标准,不管是现在的标准)的原因之一就是让那些知道MSVC问题的人(即C89编译器,而不是C99或C11编译器)知道它不适用于它。每次我写一个需要C99或更高版本的答案时,我不会选择抨击MS;我没有足够的时间,它不会实现任何有用的。 –

0

因为这是语言的定义......我不认为除了“编写编译器以使其更难”之外,还有什么特别的原因。

如果您有C++ 11编译器,则可以执行b = T{3, 4}

+1

C++不支持复合文字。当我尝试使用'g ++ -std = C++ 11 -pedantic'时,我得到了“警告:ISO C++禁止复合文字”。 –

+0

这就是我写的开头,但认为我错了,所以当我看到其他答案时改变了它......相信你的直觉...... –