LLVM 和 GCC 的实现定义行为有什么区别?

问题描述 投票:0回答:1

我注意到 clang 文档没有指定 clang 在相关标准中指定为实现定义的情况下的行为方式。 因此很难组织 LLVM 的实现定义与 GCC 的不同之处。这只是出于我的好奇心。

根据https://github.com/llvm/llvm-project/issues/11644

The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type
The result of converting a pointer to an integer or -Xarch=v9 vice versa
是他们两个。

还有什么?

gcc clang llvm undefined-behavior implementation-defined-behavior
1个回答
0
投票

如果没记错的话,在 C89 中(也许只是在 K&R2 中),将整数类型转换为较短的 N 位有符号类型的行为被定义为简单地存储结果的底部 N 位; C99 允许实现做其他事情的可能性,但实际上,没有为任何其他行为可能更有意义的硬件平台生成 C99 实现,除非该实现通过指定整数溢出来扩展语言的语义。将以某种特定的方式陷入困境,在这种情况下,同样定义超出范围的有符号整数转换的行为可能是有意义的。 Clang、gcc 和几乎所有其他编译器在任何“正常”配置中都会以与 C89 一致的方式运行。

关于整数和指针之间的转换,始终存在一个强有力的约定,即指针和整数表示之间具有“本机”关系的目标平台的实现应该以与该关系一致的方式处理它们之间的转换。 当禁用优化时,Clang、gcc 和几乎所有其他针对常见平台的编译器都会表现相同。 启用优化后,版本 18 之前的 clang 版本有时会以与指针到整数转换的

any
无副作用方法不一致的方式处理涉及 uintptr_t 类型值的计算,如通过检查生成的代码所证明的那样对于:

#include <stdint.h>
extern int x[],y[];
int test(int *p)
{
    uintptr_t up = (uintptr_t)p * 33;
    uintptr_t ux = (uintptr_t)(x+1) * 15;        
    y[0] = 1;
    if (up*35 == ux*77)
        *p = 2;
    return y[0];
}

在 18 之前的版本中,优化器将跟踪

up*35
ux*77
的“出处”,并得出结论:如果
*p = 2;
等于
p
,则
y
不可能执行,即使这种情况可能发生如果
x
是地址空间中紧邻
y
之前的单元素数组。 我不确定版本 18 现在是否会可靠地将此类转换视为清理出处信息,但至少生成的值看起来像数字。

© www.soinside.com 2019 - 2024. All rights reserved.