char的符号,有木有
提及了这个蛋疼的问题,一个被烤焦的问题:默认情况下,在Intel处理器,是有符号的;arm处理器上,却是无符号。
这里还是以arm架构为例,先来个没有任何争议的 n<127
int main(void) { 834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 8350: e28db000 add fp, sp, #0 ; 0x0 8354: e24dd00c sub sp, sp, #12 ; 0xc char n; for (n = 0; n < 127; n++) 8358: e3a03000 mov r3, #0 ; 0x0 835c: e54b3005 strb r3, [fp, #-5] 8360: ea000002 b 8370 <main+0x24> 8364: e55b3005 ldrb r3, [fp, #-5] 8368: e2833001 add r3, r3, #1 ; 0x1 836c: e54b3005 strb r3, [fp, #-5] 8370: e55b3005 ldrb r3, [fp, #-5] 8374: e353007e cmp r3, #126 ; 0x7e //与126比较大小,若小于等于,以下就跳转,形成循环。 8378: 9afffff9 bls 8364 <main+0x18> { ; } return 0; 837c: e3a03000 mov r3, #0 ; 0x0 }
让我们越过这个signed or unsigned"是非界限",试个 n<129
int main(void) { 834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 8350: e28db000 add fp, sp, #0 ; 0x0 8354: e24dd00c sub sp, sp, #12 ; 0xc char n; for (n = 0; n < 129; n++) 8358: e3a03000 mov r3, #0 ; 0x0 835c: e54b3005 strb r3, [fp, #-5] 8360: ea000002 b 8370 <main+0x24> 8364: e55b3005 ldrb r3, [fp, #-5] 8368: e2833001 add r3, r3, #1 ; 0x1 836c: e54b3005 strb r3, [fp, #-5] 8370: e55b3005 ldrb r3, [fp, #-5] 8374: e3530080 cmp r3, #128 ; 0x80 8378: 9afffff9 bls 8364 <main+0x18> { ; } return 0; 837c: e3a03000 mov r3, #0 ; 0x0 }
看来是一模一样。既然默认是unsigned char,也就无所谓与128的比较咯。
再来个 n <128 怎么样?
int main(void) { 834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 8350: e28db000 add fp, sp, #0 ; 0x0 8354: e24dd00c sub sp, sp, #12 ; 0xc char n; for (n = 0; n < 128; n++) 8358: e3a03000 mov r3, #0 ; 0x0 835c: e54b3005 strb r3, [fp, #-5] 8360: ea000002 b 8370 <main+0x24> 8364: e55b3005 ldrb r3, [fp, #-5] 8368: e2833001 add r3, r3, #1 ; 0x1 836c: e54b3005 strb r3, [fp, #-5] 8370: e55b3005 ldrb r3, [fp, #-5] 8374: e1a03c03 lsl r3, r3, #24 //这里似乎出现了异常,先左移24位,以下再右移(thumb)24位 8378: e1a03c43 asr r3, r3, #24 //作用大家都懂得,但既然都unsigned,何必如此折腾? 837c: e3530000 cmp r3, #0 ; 0x0 8380: aafffff7 bge 8364 <main+0x18> { ; } return 0; 8384: e3a03000 mov r3, #0 ; 0x0 }
最后,再看看有符号(signed char)的情况:
int main(void) { 834c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 8350: e28db000 add fp, sp, #0 ; 0x0 8354: e24dd00c sub sp, sp, #12 ; 0xc signed char n; //有符号 for (n = 0; n < 110; n++) 8358: e3a03000 mov r3, #0 ; 0x0 835c: e54b3005 strb r3, [fp, #-5] 8360: ea000002 b 8370 <main+0x24> 8364: e55b3005 ldrb r3, [fp, #-5] 8368: e2833001 add r3, r3, #1 ; 0x1 836c: e54b3005 strb r3, [fp, #-5] 8370: e15b30d5 ldrsb r3, [fp, #-5] //有符号后确实不怎么一样:mem->reg带有了符号标记s 8374: e353006d cmp r3, #109 ; 0x6d 8378: dafffff9 ble 8364 <main+0x18> { ; } return 0; 837c: e3a03000 mov r3, #0 ; 0x0 }
字符有没有符号,其实意义不是很大,本身计算机就把它当做个数字,所谓的printf("%c",ch)也只是将一个0~127的数字经过ascii表翻译成人类能懂的语言罢了。
不过,要记住几点:
通常都会认为char默认有符号,但arm下却是无符号,所以说,这个问题是和体系相关的东西。
对于处理器来说,也就是从汇编指令的角度去看,变量占几个字节,字符有没有符号,是有不同的指令,不同的方式去执行。处理器的心还是很细致di,呵呵。