我发现这段代码使用“-fsanitize=undefined,address”和不使用它会产生不同的结果。
int printf(const char *, ...);
union {
long a;
short b;
int c;
} d;
int *e = &d.c;
int f, g;
long *h = &d.a;
int main() {
for (; f <= 0; f++) {
*h = g;
*e = 6;
}
printf("%d\n", d.b);
}
Run Code Online (Sandbox Code Playgroud)
命令行是:
$ clang -O0 -fsanitize=undefined,address a.c -o out0
$ clang -O1 -fsanitize=undefined,address a.c -o out1
$ clang -O1 a.c -o out11
$ ./out0
6
$ ./out1
6
$ ./out11
0
Run Code Online (Sandbox Code Playgroud)
Clang 版本是:
$ clang -v
clang version 13.0.0 (/data/src/llvm-dev/llvm-project/clang 3eb2158f4fea90d56aeb200a5ca06f536c1df683)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /data/bin/llvm-dev/bin
Found candidate GCC installation: /opt/rh/devtoolset-7/root/usr/lib/gcc/x86_64-redhat-linux/7
Selected GCC installation: /opt/rh/devtoolset-7/root/usr/lib/gcc/x86_64-redhat-linux/7
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
Found CUDA installation: /usr/local/cuda, version 10.2
Run Code Online (Sandbox Code Playgroud)
操作系统和平台是:
CentOS Linux release 7.8.2003 (Core).0, x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
我的问题:
为了便于阅读,我将重写代码:
\nint printf(const char *, ...);\n\nunion\n{\n long l;\n short s;\n int i;\n} u;\n\nlong *ul = &u.l;\nint *ui = &u.i;\n\nint counter, zero;\n\nint main(void)\n{\n for (; counter <= 0; counter++)\n {\n *ul = zero;\n *ui = 6;\n }\n printf("%d\\n", u.s);\n}\nRun Code Online (Sandbox Code Playgroud)\nu.s这里唯一有问题的代码是在 中使用printf,whenu.s不是存储的联合体的最后一个成员。这是由 C 2018 6.5.2.3 定义的,其中表示 的值u.s是指定成员的值,注释 99 澄清了这意味着,如果s不是最后用于存储值的成员,则相应的字节将被重新解释为short。这是众所周知的。
其他代码很普通:*ul = zero;将值存储在联合成员中。不存在违反别名的情况,因为ul指向 along并用于访问 a long。*ui = 6;将值存储在另一个联合成员中,也不是别名违规。
用于表示 an 中的 6 的特定字节int是在排序和填充位方面由实现定义的。然而,无论它们是什么,无论有没有 Clang\xe2\x80\x99s \xe2\x80\x9csanitization\xe2\x80\x9d,它们都应该是相同的,并且在优化级别 0 和 1 中都应该相同。因此,相同的结果应该是在所有编译中获得。
这是一个编译器错误。
\n我同意其他评论并回答说这可能是 C 标准中的一个缺陷,因为它使得别名规则基本上毫无用处。尽管如此,示例代码符合 C 标准的要求,并且应该按照描述的方式工作。
\n| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |