我使用 Linux x86_64,GCC 4.70。并且出现了相同的错误。
我编译代码,并使用 gdb 来反汇编执行文件。以下是我得到的内容。
(gdb) l
1 int main(){
2 unsigned char a = 0xff
3 unsigned char b = 0xff
4 a = a | b
5 a = (unsigned char)(b & 0xf)
6 a |= (unsigned char)(b & 0xf)
7 return 0
8 }
(gdb) b 4
Breakpoint 1 at 0x4004a8: file test.c, line 4.
(gdb) b 5
Breakpoint 2 at 0x4004af: file test.c, line 5.
(gdb) b 6
Breakpoint 3 at 0x4004b9: file test.c, line 6.
(gdb) r
Starting program: /home/spyder/stackoverflow/a.out
Breakpoint 1, main () at test.c:4
4 a = a | b
(gdb) disassemble
Dump of assembler code for function main:
0x000000000040049c <+0>: push %rbp
0x000000000040049d <+1>: mov %rsp,%rbp
0x00000000004004a0 <+4>: movb $0xff,-0x1(%rbp)
0x00000000004004a4 <+8>: movb $0xff,-0x2(%rbp)
=> 0x00000000004004a8 <+12>: movzbl -0x2(%rbp),%eax
0x00000000004004ac <+16>: or %al,-0x1(%rbp)
0x00000000004004af <+19>: movzbl -0x2(%rbp),%eax
0x00000000004004b3 <+23>: and $0xf,%eax
0x00000000004004b6 <+26>: mov %al,-0x1(%rbp)
0x00000000004004b9 <+29>: movzbl -0x2(%rbp),%eax
0x00000000004004bd <+33>: mov %eax,%edx
0x00000000004004bf <+35>: and $0xf,%edx
0x00000000004004c2 <+38>: movzbl -0x1(%rbp),%eax
0x00000000004004c6 <+42>: or %edx,%eax
0x00000000004004c8 <+44>: mov %al,-0x1(%rbp)
0x00000000004004cb <+47>: mov $0x0,%eax
0x00000000004004d0 <+52>: pop %rbp
0x00000000004004d1 <+53>: retq
End of assembler dump.
a = a | b
被编译为
movzbl -0x2(%rbp),%eax
or %al,-0x1(%rbp)
a = (unsigned char)(b & 0xf)
编译后的结果为
mov %al,-0x2(%rbp)
and $0xf,%eax
mov %al,-0x1(%rbp)
a |= (unsigned char)(b & 0xf);
是编译成的代码。
movzbl -0x2(%rbp),%eax
mov %eax,%edx
and $0xf,%edx
movzbl -0x1(%rbp),%eax
or %edx,%eax
mov %al,-0x1(%rbp)
在汇编代码中没有出现显式转换。问题出在执行 (b & 0xf) 操作时,操作的输出是 sizeof(int)
。
因此,你应该使用以下代码:
a = (unsigned char)(a | (b & 0xF));
PS:显式转换不会产生任何警告,即使您会失去一些东西。