Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 当一个int被转换为一个短的并且被截断时,如何确定新的值?_C_Casting_Truncate - Fatal编程技术网

C 当一个int被转换为一个短的并且被截断时,如何确定新的值?

C 当一个int被转换为一个短的并且被截断时,如何确定新的值?,c,casting,truncate,C,Casting,Truncate,有人能澄清一下在C语言中将整数转换为short时会发生什么吗?我使用的是Raspberry Pi,所以我知道int是32位,因此short必须是16位 例如,我使用以下C代码: int x = 0x1248642; short sx = (short)x; int y = sx; 我知道x会被截断,但有人能解释一下到底是怎么截断的吗?轮班吗?一个数字从32位到底是如何被截断为16位的?只需将高16位从整数中截断即可。因此,您的short将变成0x8642,实际上是负数-3116632位的值将被

有人能澄清一下在C语言中将整数转换为
short
时会发生什么吗?我使用的是Raspberry Pi,所以我知道
int
是32位,因此
short
必须是16位

例如,我使用以下C代码:

int x = 0x1248642;
short sx = (short)x;
int y = sx;

我知道
x
会被截断,但有人能解释一下到底是怎么截断的吗?轮班吗?一个数字从32位到底是如何被截断为16位的?

只需将高16位从整数中截断即可。因此,您的short将变成
0x8642
,实际上是负数
-31166
32位的值将被截断为16位,就像您将32厘米长的香蕉面包塞进16厘米长的平底锅中一样。它的一半可以放进去,仍然是香蕉面包,其余的将“消失”。sx的值将与x的2个最低有效字节相同,在这种情况下,它将是0x8642(如果解释为16位有符号整数),十进制为-31166。

根据ISO C标准,将整数转换为有符号类型时,如果值超出目标类型的范围,则结果是实现定义的。(或者可以发出实现定义的信号,但我不知道有哪种编译器可以这样做。)

int y   =   sx;
实际上,最常见的行为是丢弃高阶位。因此,假设
int
为32位,
short
为16位,转换值
0x1248642
可能会产生类似
0x8642
的位模式。假设有符号类型(几乎在所有系统上都使用)采用二补表示,高阶位就是符号位,因此结果的数值将是
-31166

int y   =   sx;
这还涉及从
short
int
的隐式转换。由于
int
的范围保证至少覆盖
short
的整个范围,因此该值保持不变。(由于在您的示例中,
sx
的值恰好为负值,因此表示的这种变化可能涉及符号扩展,将
1
符号位传播到结果的所有16个高阶位。)

正如我所指出的,这些细节都不是语言标准所要求的。如果确实要将值截断为更窄的类型,最好使用无符号类型(具有语言指定的环绕行为)和显式掩蔽操作,如下所示:

unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;
如果您有一个32位的量,您希望将其放入一个16位变量中,那么您应该做的第一件事是确定如果该值不合适,您希望代码如何运行。一旦确定了这一点,您就可以知道如何编写满足您需求的C代码。有时,截断恰好是您想要的,在这种情况下,您的任务将很容易,特别是如果您使用的是无符号类型。有时,超出范围的值是一个错误,在这种情况下,您需要检查它并决定如何处理错误。有时,您可能希望值饱和,而不是截断,因此需要编写代码来实现这一点


了解C语言中的转换是如何工作的很重要,但是如果你从这个问题开始,你可能是从错误的方向来解决问题。

截断发生在CPU寄存器中。它们有不同的大小:8/16/32/64位。现在,您可以想象这样一个寄存器:

<--rax----------------------------------------------------------------> (64-bit)
                                    <--eax----------------------------> (32-bit)
                                                      <--ax-----------> (16-bit)
                                                      <--ah--> <--al--> (8-bit high & low)
01100011 01100001 01110010 01110010 01111001 00100000 01101111 01101110
现在,编译器在寄存器中加载
x
。从中,它只需加载最低有效16位(即,
ax
)并将其存储到
sx



*为了简单起见,没有考虑到Endianness

也许让代码自己说:

#include <stdio.h>

#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
   ((byte) & 0x80 ? 1 : 0), \
   ((byte) & 0x40 ? 1 : 0), \
   ((byte) & 0x20 ? 1 : 0), \
   ((byte) & 0x10 ? 1 : 0), \
   ((byte) & 0x08 ? 1 : 0), \
   ((byte) & 0x04 ? 1 : 0), \
   ((byte) & 0x02 ? 1 : 0), \
   ((byte) & 0x01 ? 1 : 0) 

int main()
{
    int x    =   0x1248642;
    short sx = (short) x;
    int y    =   sx;

    printf("%d\n", x);
    printf("%hu\n", sx);
    printf("%d\n", y);

    printf("x: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(x>>24), BYTETOBINARY(x>>16), BYTETOBINARY(x>>8), BYTETOBINARY(x));

    printf("sx: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>8), BYTETOBINARY(y));

    printf("y: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>24), BYTETOBINARY(y>>16), BYTETOBINARY(y>>8), BYTETOBINARY(y));

    return 0;
}
正如您所看到的,
int
->
short
按预期生成较低的16位

short
强制转换为
int
将产生设置了16个高位的
short
。然而,我怀疑这是特定于实现且未定义的行为。实际上,您将16位内存解释为一个整数,该整数将额外读取16位内存中的任何垃圾(如果编译器很好,希望帮助您更快地发现错误,则为1)

我认为这样做应该是安全的:

int y = 0x0000FFFF & sx;
很明显,您将无法恢复丢失的位,但这将保证高位正确归零

如果有人能用权威的参考来验证short->int高位行为,那将不胜感激


注意:二进制宏改编自。

尽管我认为使用高位还是低位是与实现相关的?@Link结果完全是根据语言标准定义的实现,但我不相信有任何编译器会为您提供高位。@Link:不,它不是与实现相关的。任何对较窄类型的转换都将始终切断最重要的位。对于不同宽度类型的并集,If会有所不同-这里的大端和小端将产生差异。但对于上述情况,情况都是一样的。@ZbynekVyskovsky-kvr000:不,将超出范围的值转换为有符号类型的结果是实现定义的。见第6.3.1.3节。(丢弃高阶位肯定是最常见的行为。)@KeithThompson:奇怪,我一直认为编译器在这里对于无符号和有符号类型是一致的。幸运的是,它们的作用都与无符号值相同,否则许多软件将停止工作……请注意,强制转换(与大多数强制转换一样)是不必要的。您可以声明
short sx=x
,并且
x
的值将隐式转换为
short
。不同平台的“int”和“short”的实际大小可能会有所不同。但是是的,假设“int”是32位,“short”是16位:1)是的,强制转换将把值从32位截断到16位
int y = 0x0000FFFF & sx;