我想定义一个函数,它接受一个 unsigned int
作为参数,并将一个 int
全等模 UINT _ MAX + 1返回给参数。
第一次尝试可能是这样的:
int unsigned_to_signed(unsigned n)
{
return static_cast<int>(n);
}
但是任何语言律师都知道,对于大于 INT _ MAX 的值,从无符号到有符号的转换是实现定义的。
我想要实现这样的功能: (a)它只依赖于规范要求的行为; (b)它在任何现代机器和编译器最佳化上都编译成禁止操作。
至于奇异的机器... 如果对于无符号整型没有符号整型同余模 UINT _ MAX + 1,假设我想抛出一个异常。如果有不止一个(我不确定这是否可能) ,让我们假设我想要最大的一个。
好吧,第二次尝试:
int unsigned_to_signed(unsigned n)
{
int int_n = static_cast<int>(n);
if (n == static_cast<unsigned>(int_n))
return int_n;
// else do something long and complicated
}
当我不使用典型的二补体系统时,我不太关心效率,因为在我看来这是不可能的。如果我的代码成为2050年无处不在的星等系统的瓶颈,那么,我打赌有人可以找到并优化它。
现在,第二次尝试非常接近我想要的。尽管对于某些输入,对 int
的转换是实现定义的,但是标准保证了对 unsigned
的转换能够保留模 UINT _ MAX + 1的值。所以这个条件确实检查了我想要的东西,并且在我可能遇到的任何系统上它都不会被编译成任何东西。
但是... ... 我仍然在向 int
转换,而没有首先检查它是否会调用实现定义的行为。在2050年的某个假设系统上,它可能会做出不知道什么事情。假设我想避免这种情况。
问题: 我的“第三次尝试”应该是什么样子的?
总结一下,我想说的是:
[更新]
让我举个例子来说明为什么这不是一个无关紧要的问题。
考虑一个假设的 C + + 实现,它具有以下属性:
sizeof(int)
等于4sizeof(unsigned)
等于4INT_MAX
等于32767INT_MIN
等于 -2 32 + 32768UINT_MAX
等于232-1int
上的算法是模232(在 INT_MIN
到 INT_MAX
的范围内)std::numeric_limits<int>::is_modulo
是真的n
转换为 int 将保留0 < = n < = 32767的值,否则将生成 零在这个假设的实现中,每个 unsigned
值恰好有一个 int
值同余(mod UINT _ MAX + 1)。所以我的问题很明确。
我声称这个假设的 C + + 实现完全符合 C + + 98、 C + + 03和 C + + 11规范。我承认我没有记住所有的单词... ... 但是我相信我已经仔细阅读了相关的章节。所以如果你想让我接受你的答案,你要么(a)引用一个规范来排除这个假设的实现,要么(b)正确处理它。
事实上,正确的答案必须处理标准所允许的 每个假设实现。根据定义,这就是“仅调用标准强制行为”的含义。
顺便说一句,请注意,由于多种原因,std::numeric_limits<int>::is_modulo
在这里完全没有用处。首先,即使无符号到有符号强制转换对于大的无符号值不起作用,它也可以是 true
。另一方面,它可以是 true
,甚至在一个人的补充或符号幅度系统,如果算术是简单的模整数范围。诸如此类。如果你的答案取决于 is_modulo
,那就错了。
[更新2]
Hvd 的回答 教会了我一些东西: 我假设的用于整数的 C + + 实现是现代 C 所允许的 没有。C99和 C11标准对于有符号整数的表示非常具体; 实际上,它们只允许二补、一补和符号大小(6.2.6.2节(2) ;)。
但是 C + + 不是 C。事实证明,这个事实正是我问题的核心。
最初的 C + + 98标准是基于更老的 C89,它说(3.1.2.5节) :
对于每个有符号整数类型,都有一个对应的(但是 不同)无符号整数类型(用关键字指定) 使用相同数量的存储(包括符号) 信息) ,并具有相同的对齐要求 有符号整数类型的非负值是 对应的无符号整数类型,以及 每种类型中的相同值是相同的。
C89没有提到只有一个符号位或只允许两个补码/一个补码/符号量级。
C + + 98标准几乎一字不差地采用了这种语言(3.9.1节第(3)段) :
对于每个有符号整数类型,都存在一个对应的 (但不同) 无符号整数类型: “
unsigned char
”,“ < code > unsigned 短 int ”、“unsigned int
”和“unsigned long int
”,分别是 它占用相同的存储量并具有相同的对齐方式 要求(3.9)作为相应的有符号整数类型; 是,每个 有符号整数类型具有与 其相应的 无符号整数无符号整数类型。非负的范围 有符号整数类型的值是相应的 无符号整数类型,以及每个 相应的有符号/无符号类型必须相同。
C + + 03标准和 C + + 11使用基本相同的语言。
据我所知,没有任何标准 C + + 规范将其有符号整数表示约束到任何 C 规范中。而且没有强制要求一个单一的符号位或任何类似的东西。它所说的只是 非阴性有符号整数必须是对应的无符号整数的一个子范围。
因此,我再次声明 INT _ MAX = 32767和 INT _ MIN =-232 + 32768是允许的。如果你的回答假设不是这样,那么它是不正确的,除非你引用 C + + 标准来证明我是错误的。