首先,我尝试 sizeof (签名短),输出为2个字节。
BUT 当我尝试通过签名短语的十六进制表示进行检查时,结果是4个字节:
#include <stdio.h>
void main(){
signed short test ;
test=-17; /* any number */
printf(" -17 when viewed as signed short Hexa is \t %x\n ", test);
}`
输出:
-17 when viewed as signed short Hexa is ffffffef
ffffffef表示32位而不是16位!
答案 0 :(得分:2)
说明符%x
需要一个整数,编译器会自动将short
转换为int
,然后再将其打印出来。
如果您的类型是有符号类型,编译器也会执行符号扩展,这意味着如果值为负,它将传播到int的高位字。即如果我们将-17=0xffef
短暂转换为int,我们将oxffffffef
。如果我们有一个像17=0x11
这样的正值,那么对于一个int也会是0x11
,并打印为0x11
。
所以你做的测试毫无意义
另一方面,类型(int
,short
等)的大小取决于编译器和/或机器,并且使用sizeof()
运算符是检查其大小的正确方法。
答案 1 :(得分:2)
printf
是一个varargs函数;它的原型是:
int printf(const char *format, ...);
这意味着第一个参数的类型为const char*
,其余参数没有指定的类型。
没有指定类型的参数会经历默认参数提升:
float
参数转换为double
。
严格比int
更窄的整数类型(有符号和无符号)转换为signed int
。
所有其他参数均未更改。
这在调用printf
之前发生,并且不以printf
为特定。调用任何varargs函数的参数(原型中有...
)。
Varargs函数无法知道它们的参数类型,所以它们需要有一些约定,让调用者告诉函数期望什么类型。在printf
的情况下,类型在格式字符串中指定,printf
使用格式字符串中指定的类型,期望它是正确的。如果你通过告诉某个参数属于某种类型,当它实际上是一个不同的类型而欺骗printf
时,结果的行为是不确定的,偶尔也会是灾难性的(虽然通常它只是意味着错误的东西是打印。)
Printf知道默认参数促销。因此,如果你告诉它期望一个无符号的短片,那么它实际上会期望int
(如果int
宽于unsigned short
)或unsigned int
如果{ {1}}和int
的大小相同。
格式项的类型是使用格式代码指定的(例如short
和d
,分别是有符号和无符号x
)和可能的修饰符。特别是,修饰符int
会将期望从h
更改为int
,而short
会将其更改为hh
。 (它不会影响签名。)
因此,如果您提供签名的char
,则应使用格式代码short
。如果提供无符号短整数,则应使用%hd
或%hu
,具体取决于您希望输出是十进制还是十六进制。无法指定带符号参数的十六进制转换,因此您需要将参数强制转换为无符号类型,以便使用十六进制格式代码:
%hx
首先将printf("This signed short is printed as unsigned: %hx\n",
(unsigned short)x);
从x
转换为short
;然后(因为默认参数促销,假设unsigned short
实际上比short
更短)到int
。 int
是实际发送到int
的内容。当printf
看到printf
格式代码时,它知道它应该预期%hx
的默认促销(即unsigned short
);它需要int
并将其转换回int
,然后打印出来。
许多程序员只会在没有演员的情况下编写unsigned short
,就像你一样。从技术上讲,这是不明确的行为,上面相当晦涩的表达是正确但迂腐的。但是,值得注意的是它产生了预期的值,而没有强制转换的不正确的%x
格式代码却没有。
答案 2 :(得分:1)
Wikipedia有一些nice tables显示不同类型整数的不同最小/最大大小,包括short int
:
短签名整数类型。能够至少含有[-32767, +32767]范围;因此,它的大小至少为16位。
这意味着如果您希望代码是跨平台和交叉编译器,则应将short int
视为不大于16位。但是如果你需要实际大小(用于在运行时计算数据长度),你仍然应该使用sizeof(short int)
,因为在某些平台上short int
可能是32位。