user-0 提问: c语言中将有符号short值赋给无符号int，出现一些难以理解的结果，请指点

回复:
user: user-0
content: unsigned short a = -32767； printf("%d",a);   //输出结果为32769 printf("%u",a);    //输出结果为32769 所以问题的关键不在于%d和%u，而在于短字节数向长字节数赋值时的扩展位

user: user-0
content: 懂了，谢谢各位。感觉编译器对这种赋值的处理不太合理，扩展位按照右值的符号类型，而不是按照左边变量的符号类型，这样用来传递signed char的值时会出错。printf函数打印的时候又涉及了实际参数向形式参数赋值，所以才会出现问题

user: user-1
content: b本身是一个正数，%d会导致把b强制转成负数即-32767后打印输出，这个很基础的东东，要用%u。

user: user-2
content: 下面来分析下： short类型占两个字节，而unsigned int占4个字节，把short型数据赋值给int或者unsigned int型数据时，如果short型数据是负的，则扩展的比特位全是1,；如果short型数据是正的，则扩展的比特位全是0. -32767的补码（计算机中都是按补码存的这个楼主应该知道吧）是1000 0000 0000 0001 但在计算机中存储的形式却是0000 0001 1000 0000（因为我们的电脑一般都是小端模式，即低位字节低地址） 将该值赋给unsignd int时，起初的unsigned int存储的二进制为0000 0000 0000 0000 0000 0000 0000 0000 （打印语句1） 变成了0000 0001 1000 0000 1111 1111 1111 1111（因为short是负值，所以用1扩展） （打印语句2） 无符号数和有符号数 在存储上并没有区别 在使用的时候 如果符号不匹配 C会做自动转换 你要用%u输出才能得到正确的值FFFF8001（十进制就是4294934529）（打印语句3） 注：我这里用union能清晰的看到int在内存中的存储

user: user-0
content: 跟输出函数关系不大，我关心的是变量b内存中实际的01代码，比如讲char变量赋值给int，关心的是char变量的ASCII码是否正确储存在int变量中

user: user-3
content: 乍看起来c++的cin、cout、ifstream、ofstream在输入、输出上比c的scanf、printf、fscanf、fprintf、fread、fwrite简单，不用格式控制符！ 但是不用格式控制符，输入输出恰好是你期望的格式的时候好说；等到输入输出不是你期望的格式的时候，你就会觉得还是用格式控制符更方便、更靠谱。 摒弃cin、cout、ifstream、ofstream！ 使用scanf、printf、fscanf、fprintf、fread、fwrite。

user: user-4
content: printf输出无符号整数的格式符是 %u 有符号的才用 %d

user: user-5
content: 我觉得可能是你在输出时使用%d的原因

user: user-5
content: 事实上，我在用C++用cout<<b<<endl; 来输出时，是没问题的

user: user-0
content: 这个问题可能在下面的场合会出现，比如要将一个char类型的变量赋值给一个无符号整型数，如果char的值大于等于128，并且假设char变量为signed类型，则会出现错误，并且这种bug挺隐蔽的

user: user-0
content: 引用 16 楼 sdghchj 的回复:[quote=引用 14 楼 yolzin 的回复:] [quote=引用 13 楼 sdghchj 的回复:] [quote=引用 10 楼 yolzin 的回复:] unsigned short a = -32767； printf("%d",a);   //输出结果为32769 printf("%u",a);    //输出结果为32769 所以问题的关键不在于%d和%u，而在于短字节数向长字节数赋值时的扩展位 我该怎么说你好，人家用的是unsiged int 去格式化成字符串，你拿个unsighed short直接格式化能说明啥问题？[/quote] 没看懂你的意思，不过这个问题我已经搞懂了，举这个例子是为了说明问题，谢谢[/quote] unsigned short a = -32767；实际上a就是32769，用%d或者%u去格式化时，都是先将其转成4字节整数，而不论是有符号还是无符号的4字节，最高位都是0，值是32769，还在65535范围内，远小于2的31次方。楼主是short a = -32767;  unsigned int b = a;此时两字符有符号先转成4字节有符号，最高位符号1不变，再转成无符号，其数值范围已经超过2的31次方了，所以用%d和%u正负是不一样的。[/quote] 我觉得printf("%d")的形式参数为signed int，printf（“%u“）的形式参数为unsigned int，拿unsigned int b作为实际参数时存在一个复制操作，unsigned int b的最高位为1，因此再给有符号int和无符号int赋值后对最高位的定义不同所以输出的结果不一样

user: user-1
content: 引用 14 楼 yolzin 的回复:[quote=引用 13 楼 sdghchj 的回复:] [quote=引用 10 楼 yolzin 的回复:] unsigned short a = -32767； printf("%d",a);   //输出结果为32769 printf("%u",a);    //输出结果为32769 所以问题的关键不在于%d和%u，而在于短字节数向长字节数赋值时的扩展位 我该怎么说你好，人家用的是unsiged int 去格式化成字符串，你拿个unsighed short直接格式化能说明啥问题？[/quote] 没看懂你的意思，不过这个问题我已经搞懂了，举这个例子是为了说明问题，谢谢[/quote] unsigned short a = -32767；实际上a就是32769，用%d或者%u去格式化时，都是先将其转成4字节整数，而不论是有符号还是无符号的4字节，最高位都是0，值是32769，还在65535范围内，远小于2的31次方。楼主是short a = -32767;  unsigned int b = a;此时两字符有符号先转成4字节有符号，最高位符号1不变，再转成无符号，其数值范围已经超过2的31次方了，所以用%d和%u正负是不一样的。

user: user-0
content: 引用 11 楼 user-7 的回复:以下假设 sizeof(short) == 2 , sizeof(int) == 4 。（在不同的配置下，可能有不同的结论） #include <stdio.h> int main() {     short a = -32767; 1) -32767 是 int 2) -32767 将通过类型转换转换为 short     根据类型转换的规则，由于 short 可以表示 -32767，转换结果为 -32767 (short 类型)   unsigned int b = a; 3) 这里也有一个类型转换。     由于 unsigned int 无法表示 -32767 ，根据无符号整数的类型转换规则，结果 b 的值为 UINT_MAX + 1 - 32767   int c;   //printf("%d",c = (b<=0));   4) b <= 0;     b 为 unsigned int ， 0 为 int 。     经过整型提升，两侧类型不变。结果两侧类型不同。    根据Usual arithmetic conversions 规则，两侧都被转化为 unsigned int 。    经过类型转化后，两侧值不变，b <= 0 结果为真，结果为 1 ，类型为 int 。（C 语言关系运算符结果为 int ） 5) c = (b<=0)     赋值号两侧均为 int ，无需类型转换，结果为1 6) c = (b<=0) 位于 printf 的 ... 参数的位置，需要进行整型提升。提升结果类型与值均不变   printf("%d",b); 7) b 为 unsigned int ，位于 printf  ... 参数的位置，需要进行整型提升。提升结果，类型与值均不变。 8) "%d" 用于输出 int ，而参数类型（经提升后）为 unsigned int 。根据 printf 的协议，两者不一致是为“未定义行为”     “未定义行为”意味着可能出现任何结果：包括但不限于：产生期望的结果，产生未期望的结果，产生随机结果，产生无法解释的结果，运行时错误，编译错误，等等 ... (在 gcc 的某些版本的特定编译选项组合下，这里确实会是一个 warning 或 error） 9) printf 不会根据类型标识符对参数进行类型转换。 10) 输出无符号整型，需要使用 %u 。   return 0; }  感觉有些地方有错误

user: user-0
content: 引用 13 楼 sdghchj 的回复:[quote=引用 10 楼 yolzin 的回复:] unsigned short a = -32767； printf("%d",a);   //输出结果为32769 printf("%u",a);    //输出结果为32769 所以问题的关键不在于%d和%u，而在于短字节数向长字节数赋值时的扩展位 我该怎么说你好，人家用的是unsiged int 去格式化成字符串，你拿个unsighed short直接格式化能说明啥问题？[/quote] 没看懂你的意思，不过这个问题我已经搞懂了，举这个例子是为了说明问题，谢谢

user: user-1
content: 引用 10 楼 yolzin 的回复:unsigned short a = -32767； printf("%d",a);   //输出结果为32769 printf("%u",a);    //输出结果为32769 所以问题的关键不在于%d和%u，而在于短字节数向长字节数赋值时的扩展位 我该怎么说你好，人家用的是unsiged int 去格式化成字符串，你拿个unsighed short直接格式化能说明啥问题？

user: user-6
content: 引用 3 楼 wang0635 的回复:printf输出无符号整数的格式符是 %u 有符号的才用 %d+1

user: user-7
content: 以下假设 sizeof(short) == 2 , sizeof(int) == 4 。（在不同的配置下，可能有不同的结论） #include <stdio.h> int main() {     short a = -32767; 1) -32767 是 int 2) -32767 将通过类型转换转换为 short     根据类型转换的规则，由于 short 可以表示 -32767，转换结果为 -32767 (short 类型)   unsigned int b = a; 3) 这里也有一个类型转换。     由于 unsigned int 无法表示 -32767 ，根据无符号整数的类型转换规则，结果 b 的值为 UINT_MAX + 1 - 32767   int c;   //printf("%d",c = (b<=0));   4) b <= 0;     b 为 unsigned int ， 0 为 int 。     经过整型提升，两侧类型不变。结果两侧类型不同。    根据Usual arithmetic conversions 规则，两侧都被转化为 unsigned int 。    经过类型转化后，两侧值不变，b <= 0 结果为真，结果为 1 ，类型为 int 。（C 语言关系运算符结果为 int ） 5) c = (b<=0)     赋值号两侧均为 int ，无需类型转换，结果为1 6) c = (b<=0) 位于 printf 的 ... 参数的位置，需要进行整型提升。提升结果类型与值均不变   printf("%d",b); 7) b 为 unsigned int ，位于 printf  ... 参数的位置，需要进行整型提升。提升结果，类型与值均不变。 8) "%d" 用于输出 int ，而参数类型（经提升后）为 unsigned int 。根据 printf 的协议，两者不一致是为“未定义行为”     “未定义行为”意味着可能出现任何结果：包括但不限于：产生期望的结果，产生未期望的结果，产生随机结果，产生无法解释的结果，运行时错误，编译错误，等等 ... (在 gcc 的某些版本的特定编译选项组合下，这里确实会是一个 warning 或 error） 9) printf 不会根据类型标识符对参数进行类型转换。 10) 输出无符号整型，需要使用 %u 。   return 0; }