![](/img/trans.png)
[英]Why do clang and gcc produce this sub-optimal output (copying a struct) for passing a pointer to a by-value struct arg?
[英]Why do GCC and Clang produce different output with variable length array?
为什么 GCC 和 Clang 使用这个符合 C 的代码产生不同的 output:
int (puts) (); int (main) (main, puts) int main;
char *puts[(&puts) (&main["\0April 1"])]; <%%>
即使使用-Wall -std=c18 -pedantic
,编译器也不会产生任何警告或错误,但程序在使用 GCC 构建时不产生 output但在使用 Clang 构建时打印当前日期。
为什么 GCC 和 Clang 使用这个符合 C 的代码产生不同的 output:
int (puts) (); int (main) (main, puts) int main; char *puts[(&puts) (&main["\0April 1"])]; <%%>
首先,它是符合规范的代码,尽管它确实使用了可变长度数组,这是 C11 和 C17 中的可选语言功能。 一些混淆是
<%
和%>
,分别表示与{
和}
相同的意思。puts
的前向声明表明它不是原型main
的 K&R 风格定义
main()
的参数使用非常规标识符puts
和main
)main
用于程序入口点以外的其他内容 function[]
) 的操作数的常规顺序的反转
一个不太混淆的等价物是
int puts();
int main(
int argc,
char *argv[ puts("\0April 1" + argc) ]
) {
}
但是,关于使用 GCC 编译的版本与使用 Clang 构建的版本之间的行为差异的核心问题归结为是否在运行时计算 VLA function 参数大小的表达式。
语言规范说,当 function 参数声明为数组类型时,其类型被“调整”为相应的指针类型。 这同样适用于完整、不完整和可变长度数组类型,但规范并未明确说明不评估维度的表达式。 它确实指定表达式 go 在某些其他情况下未计算,并且它甚至在涉及 VLA 的sizeof
表达式的情况下对此类规则进行了例外处理,因此在这种情况下的遗漏可以解释为有意义。
这仅对 VLA 类型的参数有影响,因为只有那些维度表达式的评估才能对机器 state 产生副作用,包括但不限于可观察的程序行为。
GCC 没有在运行时评估 VLA 参数的大小表达式,我倾向于认为这符合标准的意图。 结果,GCC 编译的程序除了以状态 0 退出外什么都不做。
Clang 会在运行时计算 VLA 参数的大小表达式。 尽管我不赞成对规范的这种解释,但我不能排除它。 当它计算大小表达式时,它使用第一个参数的传递值。 当程序在没有 arguments 的情况下运行时,第一个参数的值为 1,结果是标准库的puts
function 被调用时带有指向"\0April 1"
中的'A'
的指针。
int (puts) ();
int (main) (main, puts)
int main;
char *puts[(&puts) (&main["\0April 1"])];
{
}
有人遇到了编译器错误; 我只是不确定是谁了。 我不明白为什么任何编译器都会发出代码来评估 VLA 的大小参数作为参数。
clang output 相当奇怪。 为了让它工作,它必须在函数的 scope 中找到main
,但尽管已经遇到了puts
的声明,但还是放入了全局puts
。 通常,您可以在其自己的声明中访问变量。
如果有人在生产代码中这样做,我的回答是:“停止使用 K&R function 定义。”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.