c - C语言中如何过滤类似于 `int c = 1/0*0`的表达式?

标签 c linux

操作系统: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)*0uzero, 0 .也就是说,它仍然必须评估 zero因为它是 volatile ,但是可以自由地只产生零作为结果而不进行除法。
  • 编译器不必使用除法指令来计算除法运算符。我用 Apple Clang 11 进行了测试,它正在评估 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/

    相关文章:

    c - 如何快速确定文本文件中的行数?

    linux - 在 shell 脚本中执行命令时在双引号内转义单引号

    node.js - 带有 beaglebone 问题的 socket.io node.js

    linux - Linux 上的可移植 JRE - 可能吗?

    c - 使用 ICU C API 显示区域设置货币符号?

    c - 在 printf 中使用指针打印多个值

    C 程序使用 while 循环求所有奇数的总和,最多为 n

    命令 clear 不会接受终止信号(在无限循环中 | c 程序)

    c++ - 在 Linux 中使用 Eclipse C++ CDT

    c - 使用 dup2 重定向 printf 失败