#include <stdio.h>
int main()
{
signed char i = 0;
while (i <= 0)
{
printf("%d", i);
i = i - 1;
}
return 0;
}
#include <stdio.h>
int main()
{
signed char i = 0; // 定义类型为signed char的局部变量i并初始化为0
while (i <= 0) { // 把i的值整型提升为int,然后再与0比较,如果小于等于0,继续循环,否则退出循环
printf("%d", i); // 把i的值整型提升为int,再传入printf函数
i = i - 1; // 把i的值整型提升为int,然后减1,最后把结果转换为signed char类型赋值给i
// 当i-1的结果是-129时,这个值已经超出signed char类型可表示的值范围[-128, 127],
// C/C++标准规定对于有符号类型,这种情况其行为是implementation defined。
// 大多数编译器对这种情况是按截断处理来实现的,截取-129的低8位得到的结果是127,因此i的值变成127,然后再与0比较时退出循环
// https://en.cppreference.com/w/c/language/conversion#Integer_conversions
}
return 0;
}
// 下面是clang编译器生成的汇编码
/*
main: # @main
push rbp
mov rbp, rsp
sub rsp, 16
mov dword ptr [rbp - 4], 0
mov byte ptr [rbp - 5], 0 # rbp-5是局部变量i的地址,这里是初始化i为0
.LBB0_1: # =>This Inner Loop Header: Depth=1
movsx eax, byte ptr [rbp - 5] # movsx指令是按符号扩展拷贝,这里是整型提升i的值为int类型
cmp eax, 0 # 与0比较
jg .LBB0_3 # 如果大于0,跳出循环
movsx esi, byte ptr [rbp - 5] # 整型提升i的值为int类型,拷贝至esi寄存器,即printf的第二个参数
movabs rdi, offset .L.str # 把输出格式字符串地址拷贝至rdi,即printf的第一个参数
mov al, 0 # 返回值清零
call printf # 调用printf函数输出i的值
movsx eax, byte ptr [rbp - 5] # 整型提升i的值为int类型
sub eax, 1 # 整型提升的值减1
mov byte ptr [rbp - 5], al # 将计算结果转换为char类型赋给i
jmp .LBB0_1
.LBB0_3:
xor eax, eax
add rsp, 16
pop rbp
ret
.L.str:
.asciz "%d"
*/
参考
https://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions
https://en.cppreference.com/w/c/language/operator_arithmetic
就是i从0开始一直减1,直到i 的值小于signed char类型的范围, 数值溢出变成正数就结束循环了.
signed char 类型取值范围是 -128 到 127, 当 i 的值是 -128 时再减1就数值溢出变成 127了,而不是 -129.
127不满足 while (i <= 0)循环条件,就结束循环了
#include <stdio.h>
int main()
{
signed char i = 0; //定义i为signed char 类型取值范围是 -128 到 127, i 的初始值为0
while (i <= 0) //如果i<=0则继续循环
{
printf("%d ", i); //输出当前i的值
i = i - 1; //i的值减1, 当 i 的值是 -128 时再减1就数值溢出变成 127了,而不是 -129
}
printf("\n结束循环后 i 的值是%d", i);
return 0;
}
如有帮助,请点击我的回答下方的【采纳该答案】按钮帮忙采纳下,谢谢!
首先是头文件,里面包含循环语句的使用,然后是运行主函数main,接下来调用main函数内容。定义有符号字符i。char类型占用一个字节大小,一个字节为8B,即可储存2^8个数据。有正负之分,即-128*127,(unsigned 为无符号,单位0~255),while为循环语句的标识符。形式为while(条件){},条件成立,返回结果为1,运行{}里的内容。条件不成立,退出while循环,继续运行。当i为-128(二进制语言 1111 1111,第一位为1,表示负数,为0表示正数。)时,再减1,数值溢出。结果为127(二进制语言 0111 1111)。
转换方式:1111 1111(-128)-1,不计算第一位数字,即当成绝对值看待。为111 1111+1,结果为000 0000,再取相反数,即1000 0000的相反数0111 1111(127)。