C:声明后初始化struct变量

use*_*500 23 c c++

我最近遇到过这个,但无法弄清楚为什么语言允许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;
}
Run Code Online (Sandbox Code Playgroud)

Kei*_*son 34

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

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

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

b = (struct T){3, 4};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

b = T{3, 4};
Run Code Online (Sandbox Code Playgroud)

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

就此而言,这个:

b = {3, 4};
Run Code Online (Sandbox Code Playgroud)

也是有效的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);
Run Code Online (Sandbox Code Playgroud)

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

struct T obj;
/* ... */
{
    struct T tmp = { 3, 4 };
    obj = tmp;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 在C++中,带括号的type-id和la cast符号是非法的,但是`T {3,4}`可以解决这个问题. (3认同)
  • 这不是有效的c ++ 11语法.你必须放弃围绕类型的parens.这更加严重,因为问题*中使用的语法是*有效的C++ 11. (2认同)

Jon*_*ler 6

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

b = (struct T){ 3, 4 };
Run Code Online (Sandbox Code Playgroud)

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

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