我正在尝试使用 gcc 汇编程序扩展做一件非常简单的事情:
- 将 unsigned int 变量加载到寄存器中
- 加 1 给它
- 输出结果
编译我的解决方案时:
#include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0"
: "=r" (infinity)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (zero)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (one)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
使用以下开关:
gcc -std=c99 --pedantic -Wall -c main.c -o main.o
gcc -std=c99 --pedantic -Wall main.o -o main
我期望运行得到以下结果main
:
零、一、无穷大的值 = 0, 1, 18446744073709551615
零、一、无穷大的值 = 1, 2, 0
但我得到的结果是这样的:
零、一、无穷大的值 = 0, 1, 18446744073709551615
零、一、无穷大的值 = 60、61、59
有趣的是,如果我在第一个字符中添加一个字符printf
我得到以下逐一输出:
零、一、无穷大的值 = 0, 1, 18446744073709551615
零、一、无穷大的值 = 61, 62, 60
更有趣的是,我可以通过添加(可选)输出寄存器来修复该行为。但这会很浪费,因为使用了 2 个以上的寄存器,并且不能帮助我理解why前一件作品表现出未定义的行为。
#include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zerao, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (zero)
: "r" (zero)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (one)
: "r" (one)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (infinity)
: "r" (infinity)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
edit
编译用clang使用相同的选项也会给出未定义的行为:
零、一、无穷大的值 = 0, 1, 18446744073709551615
零、一、无穷大的值 = 2147483590、2147483591、2147483592
edit 2
正如奥拉夫的建议,我尝试过uint64_t
from stdint.h
。程序运行的结果仍然是未定义的。
#include <stdio.h>
#include <stdint.h>
//#define inf_int volatile unsigned long long
#define inf_int uint64_t
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zerao, one, infinity = %lu, %lu, %lu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (zero)
);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (one)
);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (infinity)
);
printf("value of zero, one, infinity = %lu, %lu, %lu\n", zero, one, infinity);
return 0;
}