C11相关语言正确性
C11 related language correctness
以下代码片段是 C11 standard §6.5.2.3 中的示例:
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 *p1, struct t2 *p2)
{
if (p1->m < 0)
p2->m = -p2->m;
return p1->m;
}
int g()
{
union {
struct t1 s1;
struct t2 s2;
} u;
/* ... */
return f(&u.s1, &u.s2);
}
根据 C11,g()
中的最后一行无效。为什么这样?
示例来自ISO/IEC9899:2011的§6.5.2.3结构和联合成员中的示例3。前面的段落之一是(添加重点):
¶6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.
问题中引用的代码前面有注释:
The following is not a valid fragment (because the union type is not visible within function f
).
根据突出显示的语句,这现在是有道理的。 g()
中的代码使用了公共初始序列,但这仅适用于 union
可见且在 f()
中不可见的情况。
问题也是严格别名问题之一。这是一个复杂的话题。详情请参阅 What is the strict aliasing rule?。
无论价值如何,即使在严格的警告选项下,GCC 7.1.0 也不会报告问题。即使使用 -Weverything
选项,Clang 也不会:
clang -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
-Wstrict-prototypes -Weverything -pedantic …
这是因为 "effective type" 规则。如果您看到 f
孤立,则两个参数具有不同的类型,并且允许编译器进行某些优化。
这里,p1
被访问了两次。如果 p1
和 p2
应该不同,编译器不需要为 return
重新加载 p1
的值,因为它不可能改变。
f
为有效代码,优化有效
在 g
中用同一个对象调用它是无效的,因为没有看到两者可能来自同一个 union
编译器可能不会采取措施来避免优化。
这是其中一种情况,证明调用有效的全部负担都落在函数的用户身上,如果 f
和 g
恰好在不同的翻译单元中。
以下代码片段是 C11 standard §6.5.2.3 中的示例:
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 *p1, struct t2 *p2)
{
if (p1->m < 0)
p2->m = -p2->m;
return p1->m;
}
int g()
{
union {
struct t1 s1;
struct t2 s2;
} u;
/* ... */
return f(&u.s1, &u.s2);
}
根据 C11,g()
中的最后一行无效。为什么这样?
示例来自ISO/IEC9899:2011的§6.5.2.3结构和联合成员中的示例3。前面的段落之一是(添加重点):
¶6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.
问题中引用的代码前面有注释:
The following is not a valid fragment (because the union type is not visible within function
f
).
根据突出显示的语句,这现在是有道理的。 g()
中的代码使用了公共初始序列,但这仅适用于 union
可见且在 f()
中不可见的情况。
问题也是严格别名问题之一。这是一个复杂的话题。详情请参阅 What is the strict aliasing rule?。
无论价值如何,即使在严格的警告选项下,GCC 7.1.0 也不会报告问题。即使使用 -Weverything
选项,Clang 也不会:
clang -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
-Wstrict-prototypes -Weverything -pedantic …
这是因为 "effective type" 规则。如果您看到 f
孤立,则两个参数具有不同的类型,并且允许编译器进行某些优化。
这里,p1
被访问了两次。如果 p1
和 p2
应该不同,编译器不需要为 return
重新加载 p1
的值,因为它不可能改变。
f
为有效代码,优化有效
在 g
中用同一个对象调用它是无效的,因为没有看到两者可能来自同一个 union
编译器可能不会采取措施来避免优化。
这是其中一种情况,证明调用有效的全部负担都落在函数的用户身上,如果 f
和 g
恰好在不同的翻译单元中。