user-0 提问: 函数的问题！

回复:
user: user-1
content: #include <stdio.h>  int main(){   unsigned char a = -1;   int b = 0 + a;   printf("%d \n",b);     // 他会输出 255    unsigned int aa = -1;   int bb = 0 + aa;   printf("%d \n",bb);   // 这里会是 －1    int bbb = 4294967295 ;   bbb = bbb * 2;    }  /*          subq	$32, %rsp 	leaq	L_.str(%rip), %rdi 	movb	$-1, -1(%rbp)         movzbl	-1(%rbp), %eax   // 关键的指令在这里 请看 http://www.niwozhi.net/demo_c233_i6798.html         addl	$0, %eax         // 对于unsigned做的扩展是 0扩展   如果是int，也就不需要扩展了         movl	%eax, -8(%rbp)    	movl	-8(%rbp), %esi 	movb	$0, %al 	callq	_printf 	 	leaq	L_.str(%rip), %rdi 	movl	$-1, -12(%rbp) 	movl	-12(%rbp), %esi 	addl	$0, %esi 	movl	%esi, -16(%rbp) 	movl	-16(%rbp), %esi 	movl	%eax, -20(%rbp)         ## 4-byte Spill 	movb	$0, %al 	callq	_printf    // 至于为什么编译器不报错 可能是因为 －1 并没有超出unsigned char的范围，他为什么要报错呢？要报什么样的错呢？    // 就连数组越界他都不报错 你还能指望他计算溢出报错吗？ 或许换成 X 语言的时候就报错了吧！ 再或许你能修改gcc的代码 让他报错！    */

user: user-2
content: 感觉和编译器有关，编译器竟然不报错，也是醉了好值得思考的问题

user: user-3
content: 引用 1 楼 user-10 的回复:-1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1 －1的二进制是FFFFFFFF?不才兄弟我表示不服。

user: user-4
content: 甚至不加强转都可以的： int i1 = -1; unsigned int u1 = 4294967295; int i2 = 4294967295; unsigned int u2 = -1; printf("i1: %d, %u\n", i1, i1); printf("i2: %d, %u\n", i2, i2); printf("u1: %d, %u\n", u1, u1); printf("u2: %d, %u\n", u2, u2);输出结果：i1: -1, 4294967295 i2: -1, 4294967295 u1: -1, 4294967295 u2: -1, 4294967295

user: user-4
content: 对这个函数而言返回值是 unsigned 还是 signed 都不重要，结果的二进制都是 0xFFFFFFFF。int i1 = -1; unsigned int u1 = 4294967295; int i2 = (int)u1; unsigned int u2 = (unsigned int)i1; printf("i1: %d, %u\n", i1, i1); printf("i2: %d, %u\n", i2, i2); printf("u1: %d, %u\n", u1, u1); printf("u2: %d, %u\n", u2, u2);充其量就是强转来强转去的。

user: user-5
content: 引用 15 楼 sholber 的回复:[quote=引用 14 楼 zhao4zhong1 的回复:] 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  赵四老湿，你说要依赖编译器，但编译器的行为可能各有不同，比如int，有的是16位，有的是32位，如果我信16位的反汇编结果，那是否就是真理呢？该怎么相信呢？[/quote] 没有绝对的真理。只有存在于某个现实中的相对真理。 现实世界中从来就没有未来也不会发生哪怕一次1+1=2  不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？

user: user-3
content: 引用 14 楼 zhao4zhong1 的回复:电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）  赵四老湿，你说要依赖编译器，但编译器的行为可能各有不同，比如int，有的是16位，有的是32位，如果我信16位的反汇编结果，那是否就是真理呢？该怎么相信呢？

user: user-5
content: 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时候。 （Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。）

user: user-6
content: 引用 12 楼 sholber 的回复:[quote=引用 9 楼 nwcfafniw 的回复:] [quote=引用 8 楼 sholber 的回复:] [quote=引用 6 楼 nwcfafniw 的回复:] [quote=引用 5 楼 baidu_23901483 的回复:] [quote=引用 1 楼 user-10 的回复:] -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.[/quote]  -1对应char依然还是-1，因此对应的16进制为0xffffffff，-1对应unsigned char是255，因此对应的16进制是0x000000ff。程序的输出在逻辑上是没有错的。 如果你想进一步了解编译器的行为，那么只能编译成汇编语言来看了。[/quote]  别的不说，-1对应unsigned char是255，这个可不一定。[/quote] 你的意思是，像-1这样的常量，最后在机器语言中的表现形式有可能不是“OxFFFFFFF”，而是“0XFFFFFFFE”？[/quote]  不，我的意思是，char类型的比特长度可能大于8（按规定是大于等于8）。等于8只是很多系统的典型默认值。  每个C的实现都有自己的定义。从<limits.h>中可以找到当前实现的定义长度：CHAR_BIT。[/quote] 行，多谢指教了。

user: user-3
content: 引用 9 楼 nwcfafniw 的回复:[quote=引用 8 楼 sholber 的回复:] [quote=引用 6 楼 nwcfafniw 的回复:] [quote=引用 5 楼 baidu_23901483 的回复:] [quote=引用 1 楼 user-10 的回复:] -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.[/quote]  -1对应char依然还是-1，因此对应的16进制为0xffffffff，-1对应unsigned char是255，因此对应的16进制是0x000000ff。程序的输出在逻辑上是没有错的。 如果你想进一步了解编译器的行为，那么只能编译成汇编语言来看了。[/quote]  别的不说，-1对应unsigned char是255，这个可不一定。[/quote] 你的意思是，像-1这样的常量，最后在机器语言中的表现形式有可能不是“OxFFFFFFF”，而是“0XFFFFFFFE”？[/quote]  不，我的意思是，char类型的比特长度可能大于8（按规定是大于等于8）。等于8只是很多系统的典型默认值。  每个C的实现都有自己的定义。从<limits.h>中可以找到当前实现的定义长度：CHAR_BIT。

user: user-7
content: 编译原理

user: user-8
content: 我很好奇，编译器为什么不给警告呢

user: user-6
content: 引用 8 楼 sholber 的回复:[quote=引用 6 楼 nwcfafniw 的回复:] [quote=引用 5 楼 baidu_23901483 的回复:] [quote=引用 1 楼 user-10 的回复:] -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.[/quote]  -1对应char依然还是-1，因此对应的16进制为0xffffffff，-1对应unsigned char是255，因此对应的16进制是0x000000ff。程序的输出在逻辑上是没有错的。 如果你想进一步了解编译器的行为，那么只能编译成汇编语言来看了。[/quote]  别的不说，-1对应unsigned char是255，这个可不一定。[/quote] 你的意思是，像-1这样的常量，最后在机器语言中的表现形式有可能不是“OxFFFFFFF”，而是“0XFFFFFFFE”？

user: user-3
content: 引用 6 楼 nwcfafniw 的回复:[quote=引用 5 楼 baidu_23901483 的回复:] [quote=引用 1 楼 user-10 的回复:] -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.[/quote]  -1对应char依然还是-1，因此对应的16进制为0xffffffff，-1对应unsigned char是255，因此对应的16进制是0x000000ff。程序的输出在逻辑上是没有错的。 如果你想进一步了解编译器的行为，那么只能编译成汇编语言来看了。[/quote]  别的不说，-1对应unsigned char是255，这个可不一定。

user: user-3
content: 引用 1 楼 user-10 的回复:-1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1  谁告诉你-1的二进制，是unsigned的FFFFFFFF？ 你听说过one's complement吗？ 还有，C没说一定要使用two's complement。

user: user-0
content: 引用 1 楼 user-10 的回复:-1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.

user: user-1
content: 楼上说的都对

user: user-9
content: printf("%u\n",  function()); printf("%d\n",  function()); 对比一下。

user: user-6
content: 引用 5 楼 baidu_23901483 的回复:[quote=引用 1 楼 user-10 的回复:] -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1char f() { 		return -1; } int main() { 	printf("%x\n",f()); 	printf("%d\n", sizeof(f())); 	return 0; } 为什么输出是ffffffff 和1呢？ 如果返回值类型改成unsigned char 输出变成了 ff 和1.[/quote]  -1对应char依然还是-1，因此对应的16进制为0xffffffff，-1对应unsigned char是255，因此对应的16进制是0x000000ff。程序的输出在逻辑上是没有错的。 如果你想进一步了解编译器的行为，那么只能编译成汇编语言来看了。

user: user-10
content: -1 的二进制  就是  unsigned的 FFFFFFFF的 因为你printf的 带符号整数，所以打印的还是-1