将有符号转换为无符号时,C编译器可以更改位表示吗? [英] Can a C compiler change bit representation when casting signed to unsigned?

查看:99
本文介绍了将有符号转换为无符号时,C编译器可以更改位表示吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以将例如int32_t转换为uint32_t来更改值的位表示形式?

Is it possible for an explicit cast of, say, int32_t to uint32_t, to alter the bit representation of the value?

例如,假设我具有以下联合:

For example, given that I have the following union:

typedef union {
    int32_t signed_val;
    uint32_t unsigned_val;
} signed_unsigned_t;

规范是否保证这些代码段具有相同的行为?

Are these code segments guaranteed by the spec to have the same behaviour?

uint32_t reinterpret_signed_as_unsigned(int32_t input) {
    return (uint32_t) input;
}

uint32_t reinterpret_signed_as_unsigned(int32_t input) {
    signed_unsigned_t converter;
    converter.signed_val = input;
    return converter.unsigned_val;
}

我在这里考虑使用C99.我已经看到了一些类似的问题,但是它们似乎都在讨论C ++,而不是C.

I'm considering C99 here. I've seen a few similar questions, but they all seemed to be discussing C++, not C.

推荐答案

将有符号整数类型铸造为相同宽度的无符号整数类型可以更改表示形式,如果您可以找到具有符号幅度或一补数的机器签名的陈述.但是int32_tuint32_t类型可以保证是二进制补码表示,因此在这种特殊情况下,表示不能更改.

Casting a signed integer type to an unsigned integer type of the same width can change the representation, if you can find a machine with sign-magnitude or ones-complement signed representations. But the types int32_t and uint32_t are guaranteed to be two's-complement representations, so in that particular case the representation cannot change.

有符号整数到无符号整数的转换在标准第6.3.1.3节中有很好的定义.相关算法是第二段:

Conversion of signed integer to unsigned integers is well-defined in the standard, section 6.3.1.3. The relevant algorithm is the second paragraph:

  1. 将具有整数类型的值转换为_Bool以外的其他整数类型时,如果 该值可以用新类型表示,但不变.
  2. 否则,如果新类型是无符号的,则通过重复加或 比新类型可以表示的最大值多减去一个 直到该值在新类型的范围内.
  3. ...
  1. When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
  2. Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
  3. ...

因此,实际上,结果必须是如果负数存储在2的补码中,则逐位复制会导致什么.允许符合标准的实现使用符号幅度或"1"补码;在这两种情况下,都必须修改负整数的表示形式以强制转换为无符号.

So the result has to be, in effect, what a bit-for-bit copy would have resulted in had the negative number been stored in 2's-complement. A conforming implementation is allowed to use sign-magnitude or ones-complement; in both cases, the representation of negative integers will have to be modified to cast to unsigned.

在评论中总结了一个漫长而有趣的讨论:

Summarizing a lengthy and interesting discussion in the comments:

  • 在使用int32_tuint32_t的OP中的精确示例中,如果程序编译,表示必须等于 ,因为C99需要int32_t长度为32位,无填充,并且要求int32_t使用2的补码表示.但是,它不要求这些类型存在.补码实现不能简单地定义int32_t并仍然保持一致.

  • In the precise example in the OP, which uses int32_t and uint32_t, the representations must be equal if the program compiles, because C99 requires int32_t and uint32_t to be exactly 32 bits long with no padding, and requires int32_t to use 2's-complement representation. It does not, however, require those types to exist; a ones-complement implementation could simply not define int32_t, and still conform.

我对类型校正的解释在水平线以下. @R ..向我们指出了缺陷报告从2004年开始,这似乎表明类型处理是可以的,或者会触发陷阱,该陷阱比未定义的行为更接近实现定义的行为.另一方面,该灾难恢复的建议解决方案似乎不在C11文档中,该文档说(6.2.6.1(5)):

My interpretation of type-punning is below the horizontal rule. @R.. pointed us to a Defect Report from 2004 which seems to say that type-punning is either OK or fires a trap, which is closer to implementation-defined behaviour than undefined behaviour. On the other hand, the suggested resolution of that DR doesn't seem to be in the C11 document, which says (6.2.6.1(5)):

某些对象表示形式不必表示对象类型的值.如果对象的存储值具有这种表示形式,并且由不具有字符类型的左值表达式读取,则该行为是不确定的.

Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined.

在我看来,如果参与类型之一具有陷阱表示,则类型操纵是未定义的行为(因此,如果读取类型没有陷阱,则为 not 未定义的行为表示).另一方面,不需要任何类型具有陷阱表示,并且只有少数类型被禁止具有一个:charunion类型-但不是联合类型的成员-以及其中的任何一个[u]int*K_t类型已实现.

That seems to me to be saying that type-punning is undefined behaviour if one of the participating types has a trap representation (and consequently is not undefined behaviour if the reading type does not have a trap representation). On the other hand, no type is required to have a trap representation, and only a few types are prohibited from having one: char and union types -- but not members of union types --, as well as whichever of the [u]int*K_t types are implemented.

我先前关于类型绑定的声明如下:

My previous statement on type-punning follows:

正在存储的联合具有未定义的行为.但是在不调用lagartos voladores的情况下,可以预料,如果将某个值存储为无符号然后按签名访问,则符号幅度机器或补码"机器可能会抛出硬件异常.

The storage-punning union has undefined behaviour. But without invoking lagartos voladores, it is somewhat expected that sign-magnitude or ones-complement machines may throw a hardware exception if a certain value is stored as unsigned and then accessed as signed.

ones-complement和sign-magnitude都有0的两种可能表示形式,每个都有流行的符号位.带有负号位的那个,负零",被允许作为一个陷阱值".因此,以有符号整数访问该值(甚至只是复制它)可能会触发陷阱.

Both ones-complement and sign-magnitude have two possible representations of 0, one with each popular sign bit. The one with a negative sign bit, "negative zero", is allowed to be a "trap value"; consequently, accessing the value (even just to copy it) as a signed integer could trigger the trap.

尽管C编译器有权抑制陷阱,例如通过使用memcpy或未签名的操作码复制值,但这样做不太可能,因为这会使知道她的程序正在运行的程序员感到惊讶在捕获负零的机器上,并且期望该陷阱在非法值的情况下触发.

Although the C compiler would be within its rights to suppress the trap, say by copying the value with memcpy or an unsigned opcode, it is unlikely to do so because that would be surprising to a programmer who knew that her program was running on a machine with trapping negative zeros, and was expecting the trap to trigger in the case of an illegal value.

这篇关于将有符号转换为无符号时,C编译器可以更改位表示吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆