【问题标题】:C checking for signed number representationC 检查带符号的数字表示
【发布时间】:2011-12-25 06:40:14
【问题描述】:

以下检查有符号数表示的方法在我的机器上正确检查二进制补码,但我没有补码或有符号幅度机器来检查它。代码能否正常工作,更重要的是,它是否可移植?

文件:平台.h

#ifndef PLATFORM_H
#define PLATFORM_H
#include <limits.h>

static
const union {
    signed char sc;
    unsigned char uc;
} plat_4xvYw = {.sc = -1};

#define IS_TWOS_COMPL (plat_4xvYw.uc == UCHAR_MAX)
#define IS_ONES_COMPL (plat_4xvYw.uc == UCHAR_MAX - 1)
#define IS_SIGNED_MAG (plat_4xvYw.uc == (1U << (CHAR_BIT - 1)) + 1U)

#endif

文件:a.c

#include <inttypes.h>
#include <limits.h>
#include "platform.h"
#include <assert.h>

int
main (void) {

    assert (IS_TWOS_COMPL);
    if (IS_TWOS_COMPL) {

        printf ("twos complement\n");
    } else if (IS_ONES_COMPL) {

        printf ("ones complement\n");
    } else if (IS_SIGNED_MAG) {

        printf ("signed magnitude\n");
    }
    return 0;
}

【问题讨论】:

  • 你必须非常努力才能找到一台不使用补码的计算机。我怀疑过去 20 到 30 年在学术界以外制造的任何计算机都没有它。
  • 我不是 100%,但我相信存储有符号整数并将其作为无符号整数访问是实现定义或未定义的行为。有关按位运算符,请参阅 C99 6.5 §4:“这些运算符产生的值取决于整数的内部表示,并且具有符号类型的实现定义和未定义方面。”据我了解,这个工会也必须如此。
  • @Lundin:您可以将其作为unsigned 访问(这是严格别名规则所允许的类型之一),但除非int 的值可以表示为unsigned(即不是负数),不能保证它不是unsigned 的陷阱值。所以它不是 100% 可移植的,但问题不是一般访问有符号的 int,而是特别是访问 -1
  • @steve 我的印象是char 类型不会有这样的问题,因为C 保证不会有填充位。不存在字节序问题。 C 保证存在值位的 1-1 映射。所以剩下的唯一问题是符号位是否映射到无符号的值位。鉴于 signed 和 unsigned char 必须具有相同的宽度,因此必须如此。 (话虽如此,我同意你的回答更好)
  • 我不同意“有符号和无符号字符必须具有相同的宽度”。它们使用相同的存储,但这并不意味着它们具有相同数量的填充位。当然,除非我错过了标准中的某个地方,即signed char 没有填充。

标签: c platform negative-number representation


【解决方案1】:

我认为你最好只掩盖负面的int

if ((-1 & 0x1) == 0) {
    // -1 ends in "0" => 1s' complement
} else if ((-1 & 0x2) == 0) {
    // -1 ends in "01" => sign-magnitude
} else {
    // -1 ends in "11" => two's complement
}

严格来说,这并不能告诉您与您的代码相同的内容,因为不能保证 intsigned char 使用相同的符号位含义。但是(a)认真吗?并且 (b) 这适用于 int 和更大的类型,对于较小的类型则比较棘手。 unsigned char 保证没有填充位,但signed char 没有。所以我认为拥有(例如)CHAR_BIT == 9UCHAR_MAX = 511CHAR_MAX = 127signed char 具有 1 个填充位是合法的。那么您的代码可能会失败:存储的有符号值中的符号位不一定是您期望的位置,填充位的值可能是 0 或 1。

在很多情况下,您可以只在程序中使用int8_t 而不是signed char。如果它存在,它保证是 2 的补码,因此可能会让您不必关心 signed char 的表示。如果它不存在,则程序将无法编译,这就是您asserting 的意思。您会从 2 的补码平台得到假阴性,但没有 8 位字符,因此不提供 int8_t。这可能会或可能不会打扰您...

【讨论】:

  • 澄清一下,你是否暗示负数表示可以是有符号字符的 2 的补码,另一个系统(例如 1 的补码)简称为另一个系统(例如,1 的补码),以及另一个用于 int 等......我也没有使用符号位的相同含义理解有关 int 和 signed char 的部分。
  • @tyty:是的,我的意思是 signed char 可能是 2 的补码,而 short 是 1 的补码。 6.2.6.2/2 中的标准说符号位以“以下方式之一”修改值,然后列出了符号位可以影响值的三种方式,对应于三种允许的表示形式。所以“符号位的含义”与“表示”是一样的。它没有明确说明实现是否必须为每个整数类型选择相同的“方式”,所以我认为没有这样的要求。因此,做出不同的选择是奇怪但合法的。
  • 正式地说,我认为标准中的英文是模棱两可的:“对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位...如果符号位为 1,则应通过以下方式之一修改该值”。这是否意味着“存在以下一种方式,使得对于所有类型,符号位以这种方式修改值”与“对于所有类型,存在以下方式之一,使得符号位修改以这种方式获得价值”。
  • 所以,作为一个实施者,我会假设实施者的最坏可能的意义,并让他们都一样。作为一名程序编写者,假设我们甚至关心这些奇怪的架构,我会假设程序的最坏含义,即它们可能会有所不同。有可能某处的标准有权威的评论(如缺陷报告)解决了歧义,也可能我是世界上唯一看到歧义的人,而且对其他人来说很明显这意味着什么;-)
  • 请注意,如果uint8_t 存在,则unsigned char 必须是二进制补码,或者必须使用扩展整数类型来定义它。不管怎样,CHAR_BIT 必须是 8。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 2018-06-24
  • 1970-01-01
相关资源
最近更新 更多