操作系统:Ubuntu 18.04
海湾合作委员会:7.5.0
我正在编写一个表达式生成器来测试我的简单调试器,并希望使用 division by zero
过滤表达式。行为。但是我遇到了一个令人不安的问题。
至于确定division by zero
行为类似于 int c = 1/0
,它会发出信号,以便我可以通过 signal()
处理这些情况.尽管如此,在类似于 int c = 1/0*0
的情况下, c
等于 0
,并且程序永远不会陷入 signal handler
.
测试代码如下。
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void ss(int sig){
printf("division by zero.\n");
exit(0);
}
int main(){
int c;
signal(SIGFPE, ss);
c = (1u/0u)*0u;
printf("%d\n", c);
}
这是结果。gcc -o divide_0 divide_0.c
divide_0.c: In function ‘main’:
divide_0.c:15:11: warning: division by zero [-Wdiv-by-zero]
c = (1u/0u)*0u;
^
0
在这种情况下如何捕获警告?
最佳答案
强制编译器执行除以零实际上很难:
1/0
在编译时。为了防止它知道除数为零,我们可以使用 volatile
对象,如 volatile int zero = 0; c = 1/zero;
. volatile
限定符告诉编译器该对象可能会通过它未知的方式更改,因此它不能假设它为零,并且必须在计算表达式时获取该值。(1u/0u)*0u
中乘以零即使我们将除数更改为 zero
也会适得其反.编译器可以推断 (1u/zero)*0u
的任何定义结果为零,因此允许使用零作为已定义结果(零)和未定义结果(无论编译器喜欢什么)的并集,因此可以替换 (1u/zero)*0u
与 zero, 0
.也就是说,它仍然必须评估 zero
因为它是 volatile
,但是可以自由地只产生零作为结果而不进行除法。1u/zero
指令等同于 zero == 1 ? 1 : 0;
.换句话说,它只是进行了比较和集合,而不是除法,大概是因为比较和集合更快。当我将其更改为 13u/zero
时,然后编译器使用了除法指令。我希望获得除法指令的最佳选择是使用 volatile int unknown = 0; unknown = unknown/unknown;
.即便如此,C 标准也允许编译器使用它想要的任何指令执行除法,而不是除法。但我认为在这种情况下编译器通常会生成除法指令。然后这段代码将在运行时执行一个除法。这是否会导致信号以及该信号会发生什么取决于您的计算平台。
关于c - C语言中如何过滤类似于 `int c = 1/0*0`的表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67438895/