
[英]In C programming Language: What order would 3 (Number 3) be assigned to the variables? As in which variable would receive 3 first, second and third?
[英]What is the algorithm that a compiler would use while casting signed variables to larger variable types, C language?
答案可能取决于编译器,但是;
以下行的预期 output 是什么?
signed char a = -5;
printf("%x \n", (signed short) a);
printf("%x \n", (unsigned short) a);
编译器会在将signed char
转换为更大的变量时用零 (0) 或一 (1) 填充最高有效位吗? 如何以及何时?
PS 还有其他问题。 我试图在在线编译器上运行下面的代码进行测试。 结果并不像我预期的那样。 所以我添加了详细的转换,但它没有用。 为什么printf("%x \n", (signed char)b);
的output是 4 个字节长而不是 1 个字节?
int main()
{
unsigned char a = (unsigned char)5;
signed char b = (signed char)-5;
unsigned short c;
signed short d;
c = (unsigned short)b;
d = (signed short)b;
printf("%x ||| %x ||| %x ||| %x\n", (unsigned char)a, (signed char)b, c, d);
printf("%d ||| %d ||| %d ||| %d\n", a, b, c, d);
printf("%d ||| %d ||| %d ||| %d\n", a, b, (signed char)c, (signed char)d);
return 0;
}
Output:
5 ||| fffffffb ||| fffb ||| fffffffb
5 ||| -5 ||| 65531 ||| -5
5 ||| -5 ||| -5 ||| -5
在 C 中,arguments 到等级低于int
的可变参数函数(如printf
)被转换为int
。 (不是unsigned int
除非参数是无符号的并且宽度与int
相同)。
将signed short
或signed char
转换为signed int
不会更改值。 如果您从 -5 开始,您将以 -5 结束。
但是,如果您将负符号值转换为无符号类型(例如,使用显式强制转换),则转换将以比无符号类型的最大值大一为模的方式完成。 例如, unsigned short
的最大值为 65535(在许多实现中),因此将 -5 转换为unsigned short
结果为 -5 模 65536,即 65531。(C 的%
运算符不产生数学模归约。)当那个然后 value 被隐式转换为int
,它仍然是 65531,所以这就是用%x
( fffb
) 打印的内容。
请注意,将格式%x
应用于signed int
在技术上是不正确的。 %x
要求相应的参数是一个unsigned int
。 目前,C 不保证将有符号值解释为无符号值的结果是什么,但这很快就会改变。 (这不是转换。在运行时,类型不再存在,值只是位模式。)
在C11 标准的第 6.3.1.3 节中列出了在有符号和无符号类型之间转换的确切规则:
1当 integer 类型的值转换为
_Bool
以外的另一种 integer 类型时,如果该值可以用新类型表示,则它不变。2否则,如果新类型是无符号的,则通过比新类型可以表示的最大值重复加或减一来转换值,直到该值在新类型的范围内。
3否则,新类型已签名,无法在其中表示值; 结果是实现定义的,或者引发了实现定义的信号。
至于上面这段代码的含义:
signed char a = -5;
printf("%x \n", (signed short) a);
printf("%x \n", (unsigned short) a);
这里发生了一些事情。
对于第一个printf
,您首先将signed char
转换为signed short
。 根据上面的第 1 条,由于值 -5 可以存储在两者中,因此值不会被强制转换更改。 然后,因为这个值被传递给可变参数 function,所以它被提升为int
类型,并且再次通过第 1 条,该值保持不变。
然后使用%x
格式说明符打印生成的int
值,该说明符需要一个unsigned int
。 对于不匹配的格式说明符,这在技术上是未定义的行为,尽管大多数实现将允许隐式签名/未签名重新解释。 因此,假设二进制补码表示,将打印int
值 -5 的表示,并假设 32 位int
这将是fffffffb
。
对于第二个printf
,从signed char
到unsigned short
的转换将根据上面的第 2 条发生,因为值 -5 不能存储在unsigned short
中。 假设 16 位短,这给你值 65536 - 5 = 65531。假设两个补码表示,这相当于将表示从fb
符号扩展到fffb
。 这个unsigned short
值然后在传递给printf
时被提升为int
,并且根据第 1 条,该值保持不变。 然后%x
格式说明符将其打印为fffb
。
当被转换的值可以在目标类型中表示时,integer 类型之间的转换是值保留的。 signed short
可以表示signed char
可表示的所有值,所以这...
signed char a = -5;
printf("%hd\n", (signed short) a);
...预计 output 包含“-5”的行。
但是,您的代码具有未定义的行为。 转换说明符%x
要求相应的参数具有类型unsigned int
,而您传递的是带signed short
(根据默认参数促销转换为int
)。
如果您的实现对有符号整数使用二进制补码表示(我可以肯定地断言它确实如此),则表示会将原始带signed char
符号扩展为带signed short
的宽度,然后将其符号扩展为(signed) int
的宽度。 因此,UB 在您身上的一种合理可能的表现形式……
printf("%x \n", (signed short) a);
...将是打印
fffffffb
另一种情况有点不同。 Integer 目标类型为无符号且不能表示源值的转换已明确定义。 通过以目标类型中可表示值的数量为模减少源值,将源值转换为目标类型。 因此,如果您的unsigned short
有 16 个值位,那么将 -5 转换为unsigned short
的结果是 -5 modulo 65536,即 65531。
因此,
printf("%hu\n", (unsigned short) a);
预计会打印包含“65531”的行。
同样, %x
转换说明符与相应参数的类型不匹配( (unsigned short) a
,通过默认参数提升转换为int
),因此您的printf
具有未定义的行为。 但是,在二进制补码系统上将 16 位unsigned short
转换为 32 位int
将涉及零扩展源的表示形式,因此 UB 在您的...
printf("%x \n", (unsigned short) a);
...将是打印
fffb
.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.