除以零不会导致 Nvidia Jetson 上的运行时异常

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

我不明白我的 Nvidia Jetson Nano 开发板上的以下行为。

C 代码示例:

//main.c

#include <stdio.h>

int main()
{
    int fred = 123;
    int i;

    for(i = -10 ; i <= 10 ; i++)
        printf("%d / %d == %d\n", fred, i, fred / i);

    return 0;
}

编译:

gcc main.c -ggdb

运行生成的 a.out 可执行文件会产生以下输出...

123 / -10 == -12
123 / -9 == -13
123 / -8 == -15
123 / -7 == -17
123 / -6 == -20
123 / -5 == -24
123 / -4 == -30
123 / -3 == -41
123 / -2 == -61
123 / -1 == -123
123 / 0 == 0                  //unexpected!
123 / 1 == 123
123 / 2 == 61
123 / 3 == 41
123 / 4 == 30
123 / 5 == 24
123 / 6 == 20
123 / 7 == 17
123 / 8 == 15
123 / 9 == 13
123 / 10 == 12

使用 gcc 3.7 在古老的 Pentium 4 上编译的完全相同的代码会导致(如预期)当

i
达到 0 并导致被零除时抛出运行时异常。

Nvidia 主板运行 Ubuntu 18.04 LTS、gcc 版本 7.4.0(最新),并且在其他方面都运行良好。 我还编译了该代码的等效 Ada 语言版本,并按预期引发了运行时异常 is (因为 Ada 代表我提前进行了安全检查)。

我意识到在 C 语言中,“除以零会产生未定义的行为”可能是对此的解释,但对于同一编译器套件的两个版本为同一操作提供如此不同的结果,这让我感到困惑。

什么情况会导致 Nvidia Tegra ARM(64 位)CPU 允许被零除而被操作系统忽略?

编辑: /etc/cpuinfo 中有关 CPU 的详细信息...

$ cat /proc/cpuinfo
processor       : 0
model name      : ARMv8 Processor rev 1 (v8l)
BogoMIPS        : 38.40
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x1
CPU part        : 0xd07
CPU revision    : 1

.... truncated ....
c arm integer-division divide-by-zero armv8
2个回答
10
投票

Nvidia Jetson Nano 开发板使用基于 ARMv8 架构的 ARM Cortex-A57 (Link)。 基于ARMv8的指令集spec整数除以零返回零并且不会被捕获。

2.3 除法指令

ARMv8-A 支持 32 位和 64 位大小值的有符号和无符号除法。

指令说明

SDIV 签名除法

UDIV 无符号除法

...

溢出和除零不会被捕获:

• 任何整数除以零都会返回零

因此,在这种情况下,编译器会生成

sdiv
(请参阅示例),并且CPU毫无例外地返回0。当您在不同平台上编译相同的代码时,每个其他 CPU 对除零的反应可能不同。正如您在问题中提到的,如果除以 0,则 C 标准的行为是“未定义”。


0
投票
可配置的

(请参阅STM32 Cortex®-M4 MCU 和 MPU 编程手册,第 231 页) 使事情变得更加复杂的是,编译器有时可以识别被零除的情况并生成非法指令(避免我注意到的配置)。玩一下这个

示例

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