Joh*_*itb 3 gcc posix clock integer-overflow icc
我坚信有一些奇怪的事情发生,所以我想提出这个问题.
#include <time.h>
#include <stdint.h>
// shall return a monotonically increasing time in microseconds
int64_t getMonotonicTime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
int64_t ret;
ret = ts.tv_sec * 1000000; // #1 HERE
ret += ts.tv_nsec / 1000;
return ret;
}
Run Code Online (Sandbox Code Playgroud)
有问题的行ts.tv_sec * 1000000
导致系统溢出,其中time_t
和int
32位大(在我的系统上恰好是这种情况),每次ts.tv_sec
大于2 147.
当我为这个bug编写测试用例时,我发现英特尔icc
编译器没有溢出,即使我确信它time_t
实际上也32
有点宽,即使我禁用了优化.GCC行为确实导致了预期的溢出.
除了未定义的行为,英特尔不会溢出的原因是什么?英特尔开发人员的理由是什么?或者这只是我的误解?
看看这个简单的代码:
long f(int a,int b){
return a*b;
}
Run Code Online (Sandbox Code Playgroud)
我们看到gcc生成的3个不同的asm:
movl %edi, %eax
imull %esi, %eax
cltq
Run Code Online (Sandbox Code Playgroud)
铛:
imull %esi, %edi
movslq %edi, %rax
Run Code Online (Sandbox Code Playgroud)
英特尔:
movslq %esi, %rsi
movslq %edi, %rdi
imulq %rsi, %rdi
movq %rdi, %rax
Run Code Online (Sandbox Code Playgroud)
基本上,您可以将2个32位数字相乘(imull
)然后对结果进行符号扩展.或者你可以对操作数进行符号扩展,然后将它们乘以64位数字(imulq
),那么原则上你应该只保留低32位并对它们进行符号扩展,但这是不必要的,因为重要的情况是那些存在的情况.溢出(未定义的行为),这种优化(删除最终的符号扩展)正是您所观察到的.