Type conversion warning after bitwise operations in C

后端 未结 4 1217
傲寒
傲寒 2021-02-20 05:29

How do you explain that line 7 gets a warning, but not line 5 or line 6?

int main()
{
    unsigned char a = 0xFF;
    unsig         


        
4条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-20 05:56

    I use linux x86_64, GCC 4.70. And get the same error. I compile the code, and use gdb to disassemble the execution file. Here is what I get.

    (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.
    

    the a = a | b is compiled to

    movzbl -0x2(%rbp),%eax
    or     %al,-0x1(%rbp)
    

    the a = (unsigned char)(b & 0xf) is compiled to

    mov    %al,-0x2(%rbp)
    and    $0xf,%eax
    mov    %al,-0x1(%rbp)
    

    the a |= (unsigned char)(b & 0xf); is compiled to

    movzbl -0x2(%rbp),%eax
    mov    %eax,%edx
    and    $0xf,%edx
    movzbl -0x1(%rbp),%eax
    or     %edx,%eax
    mov    %al,-0x1(%rbp)
    

    the explict cast didn't appear in asm code. The problem is when (b & 0xf) operation is done. the output of operation is sizeof(int). So you should use this instead:

    a = (unsigned char)(a | (b & 0xF));
    

    PS: explict cast dont generate any warning. even you will lose something.

提交回复
热议问题