【问题标题】:Any reason to assign -0?有什么理由分配-0?
【发布时间】:2015-12-19 12:58:15
【问题描述】:

我正在使用 Lint 浏览一些旧的 C 代码,偶然发现了这一行:

int16_t max = -0;

Lint 消息是“常量表达式在操作 '-' 中的计算结果为 0”。

有人会使用-0有什么理由吗?

【问题讨论】:

  • 如果目标架构有负的0 for int
  • 也许是波浪号 ~ 不是减号 -
  • ~0 在任何架构中都不会评估为零,AFAIK。
  • IEEE 浮点确实支持正零和负零。我不知道任何具有正零和负零的整数类型的架构。
  • @Peter:C 标准允许有符号整数的不同表示。符号/幅度就是这样的编码。不确定哪个标准 CPU 可能使用了它,但我想到了定制的 FPGA CPU 或 DSP。

标签: c numbers integer lint


【解决方案1】:

C99 或更高版本没有理由。

int16_t 是一个精确宽度的整数类型。

typedef 名称intN_t 指定宽度为 N、无填充位和 二进制补码表示的有符号整数类型。因此,int8_t 表示这种有符号整数类型,其宽度正好为 8 位。 C11dr §7.20.1.1 1

二进制补码没有带符号的零。所以代码等价于

int16_t max = 0;

IMO,int16_t max = -0;希望在非 2 的补码平台上,将 max 初始化为 -0 以标记长度为 0 的数组或仅包含值为-0的元素。

【讨论】:

    【解决方案2】:

    这适用于使用带有one's complement 编号的 CPU 的架构。

    • 一个补码是一种表示负数的方法,具有 -0。仍在用于浮点。
    • 对于无符号数,最大数确实是 -0:全为 1。

    我们习惯于二进制补码,多一个负数。虽然一个补码在零附近有一些问题,但对于 MIN_INT 附近的二进制补码也是如此:-MIN_INT == MIN_INT

    在上面的代码中可能是无符号数:

    uint16_t max = (uint16_t) -1;
    

    【讨论】:

    • 也可以是符号/大小。
    • @Olaf 是的,虽然 max 100000 将是最大有符号整数之后的数字,但不知何故没有用。
    • 嗯.. 是 binary100000 吗?为什么那会是“INT_MAX之后的数字?它是一个否定的0,至于1s补码。
    • @Olaf。对,for (int i = 0; i != max; ++i) 会是一种糟糕的用法。
    • 写这种循环的人不应该出现在我的公司。
    【解决方案3】:

    在 C 规范(6.2.6.2 整数类型) 中,它声明了以下内容(强调我的):

    对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。不需要任何填充位;应该只有一个符号位。作为值位的每个位应与相应无符号类型的对象表示中的相同位具有相同的值(如果有 有符号类型中的 M 个值位和无符号类型中的 N 个值位,则 M£N)。如果符号位为零,则不应影响结果值。 如果符号位为1,则通过以下方式之一修改该值:

    • 符号位为 0 的对应值被取反(符号和 幅度);
    • 符号位的值为 -(2N)(二进制补码);
    • 符号位的值是 -(2N - 1)(一个补码)。

    其中哪些适用是实现定义的,是否适用 符号位为 1 且所有值位为零(前两位)的值,或 带有符号位和所有值位 1(用于一个补码),是一个陷阱 表示或正常值。 在符号和大小的情况下 和一个补码,如果这个表示是一个正常值,它是 称为负零

    也就是说,C 支持三种不同的representations for signed integers,其中两种有signed zero 的概念,区分正零和负零。

    所以,我的解释是,您的代码 sn-p 的作者可能试图产生一个负零值。但是,正如Jens Gustedt's answer 中所指出的,这个表达式实际上不能产生负零,这意味着作者可能在那里做出了错误的假设。

    【讨论】:

      【解决方案4】:

      不,我看不出有什么原因。其他人提到可以有“负零”的平台,但是这个表达式永远不能产生这样的负零,所以这是没有用的。

      C标准中对应的段落是6.2.6.2 p3,重点是我的:

      如果实现支持负零,则应生成它们 仅由:

      — &、|、^、~、> 运算符,其操作数 产生这样的价值;

      — +、-、*、/ 和 % 运算符其中一个操作数为负零,结果为零;

      ——复合 基于上述情况的赋值运算符。

      例如,要在这样的平台上生成负零,您可以使用 ~INT_MAX,但对于其他表示形式,这不会是零,因此代码的可移植性不是很好。

      【讨论】:

      • 嗯:6.2.6.2 似乎甚至阻止 long mz = strtol("-0", NULL, 10) 创建 -0,即使实现支持负零。
      • @chux,是的,我想是的。整个想法是,架构应该尽可能避免负零。它们只能通过不可避免的位操作产生。
      • 我同意您的说法,但编码员可能有不同的想法,或者他使用了非标准编译器。这是一个嵌入式设备和旧代码,所以编译器很可能有一些扩展/修改(几年前很常见)。
      猜你喜欢
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-09
      • 2019-11-04
      • 2010-09-29
      • 2013-09-27
      相关资源
      最近更新 更多