3

C99 为结构引入了指定初始化器的概念。例如,给定:

typedef struct {
    int c;
    char a;
    float b;
} X;

我可以像这样初始化:X foo = {.a = '\1', .b = 2.0F, .c = 4};并且调用:printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);会输出:

c = 4
a = 1
b = 2.000000

正如这里提到的,这具有分配给cthen athen的“令人惊讶的行为”,b与我指定的初始化程序的顺序无关。

如果我有这样的功能,这将成为一个真正的问题:

int i = 0;

int f() {
    return ++i;
}

int g() {
    i += 2;
    return i;
}

int h() {
    i += 4;
    return i;
}

我想像这样初始化:X foo = {.a = (char)f(), .b = g(), .c = h()};现在当我这样做时:printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);我得到:

c = 4
a = 5
b = 7.000000

问题是没有警告我的初始化顺序没有得到遵守。是否有警告或我可以为此启用的东西?

[现场示例]

4

2 回答 2

5

您可以在 C 中做的最好的(阅读:合理的)事情是在初始化结构之前声明三个临时 const 变量。它们的声明顺序是它们初始化器的评估顺序。

像这样的东西:

const char a = f();
const float b = g();
const int c = h();

X foo = {.a = a, .b = b, .c = c};

在这种情况下,函数调用的顺序和程序员的意图很清楚。

于 2016-01-05T15:00:19.280 回答
4

...没有警告我的初始化顺序没有得到遵守

特定的初始化顺序是基于标准中规定的其他内容的期望。(正如评论中指出的那样)

C99第 6.7.9 节,p23:23 初始化列表表达式的计算相对于彼此是不确定的,因此任何副作用发生的顺序是未指定的。[强调我的]

因此,除了未定义(或未指定)行为之外,这里没有问题。与其他 C 行为非常相似,例如函数参数评估顺序的歧义。

EDIT
C99 对此有这样的说法:

来自 C99 §6.5.2.2p10:
未指定函数参数的评估顺序,未指定函数指示符、实际参数和实际参数中的子表达式的评估顺序,但在实际调用之前有一个序列点。
[强调我的]

在这里阅读更多

您更喜欢警告(您说得很好,+1)是另一回事。我不确定在 C/C++ 语言中为 -- -未定义- -行为- 提供警告有多实用。

有趣的是要注意本讨论中的一些陈述的假设/意见,为什么 C++ 标准不包括指定初始化器。(然而) ...

...C++ 更感兴趣的是把灵活性放在类型设计者的一边,因此设计者可以让正确使用类型变得容易,并且难以错误使用。

于 2016-01-05T15:19:25.073 回答