Chinaunix首页 | 论坛 | 博客
  • 博客访问: 500470
  • 博文数量: 104
  • 博客积分: 3045
  • 博客等级: 少校
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-29 10:18
文章分类

全部博文(104)

文章存档

2011年(72)

2010年(1)

2009年(1)

2008年(30)

分类: C/C++

2011-05-05 12:49:26

先看一下例子
#include

int main()
{
int i;
unsigned char *p;
char *p1;
int a[] = {0xffffffff, 0xffffffff, 0xffffffff};
p = a;
p1 = a;
for(i = 0 ; i < 8 ; i++) {
printf(" 0x%02x  0x%02x \n", p[i], p1[i]);
}
}
$ gcc main.c 
main.c: In function ‘main’:
main.c:10: warning: assignment from incompatible pointer type
main.c:11: warning: assignment from incompatible pointer type
$ ./a.out 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
 0xff  0xffffffff 
看来是在printf的参数传递过程中出现了问题,%x传递的参数的大小是四个字节,反汇编看一下
¥gcc -S main.c -o main.s
$ vi main.s
.file "main.c"
.section .rodata
.LC0:
.string " 0x%02x  0x%02x \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $48, %esp
movl $-1, 24(%esp)
movl $-1, 28(%esp)
movl $-1, 32(%esp)
leal 24(%esp), %eax
movl %eax, 40(%esp)
leal 24(%esp), %eax
movl %eax, 44(%esp)
movl $0, 36(%esp)
jmp .L2
.L3:
movl 36(%esp), %eax
addl 44(%esp), %eax
movzbl (%eax), %eax
movsbl %al, %ecx
movl 36(%esp), %eax
addl 40(%esp), %eax
movzbl (%eax), %eax
movzbl %al, %edx
movl $.LC0, %eax
movl %ecx, 8(%esp)
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
addl $1, 36(%esp)
.L2:
cmpl $7, 36(%esp)
jle .L3
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.5 20101112 (Red Hat 4.4.5-2)"
.section .note.GNU-stack,"",@progbits

可见,在printf执行的时候传递的两个参数分别使用了 movsbl 和movzbl,这两个指令有什么差别呢

movsbl、movzbl的区别:
    %dh = 8D
    %eax = 98765432

    movb %dh,%al    //%eax = 9876548D

    movsbl %dh,%eax    //%eax = FFFFFF8D
    movzbl %dh,%eax    //%eax = 0000008D

如果 我们要一个字节一个字节的打印内存的信息的时候,还是需要使用unsigned char 作为指针进行打印比较好。

看一下mips 反汇编的结果
       lw      $2,24($fp)
        slt     $2,$2,8
        beq     $2,$0,$L3
        lw      $3,28($fp)
        lw      $2,24($fp)
        addu    $2,$3,$2
        lbu     $5,0($2)
        lw      $3,32($fp)
        lw      $2,24($fp)
        addu    $2,$3,$2
        lb      $2,0($2)
        la      $4,$LC1
        move    $6,$2
        jal     printf
        lw      $2,24($fp)
        addiu   $2,$2,1
        sw      $2,24($fp)
        b       $L2
看一下arm 平台下运行的结果
# ./a.out 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
 0xff  0xff 
# cat /proc/cpuinfo 
Processor       : ARM926EJ-S rev 5 (v5l)
BogoMIPS        : 99.12
Features        : swp half thumb fastmult edsp java 
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 5

Hardware        : Atmel AT91SAM9260-EK
Revision        : 0000
Serial          : 0000000000000000

再看一下arm 的反汇编
.L3:
        ldr     r3, [fp, #-16]
        mov     r2, r3
        ldr     r3, [fp, #-12]
        add     r3, r2, r3
        ldrb    r3, [r3, #0]    @ zero_extendqisi2
        mov     r1, r3
        ldr     r3, [fp, #-16]
        mov     r2, r3
        ldr     r3, [fp, #-8]
        add     r3, r2, r3
        ldrb    r3, [r3, #0]    @ zero_extendqisi2
        ldr     r0, .L6+4
        mov     r2, r3
        bl      printf
        ldr     r3, [fp, #-16]
        add     r3, r3, #1
        str     r3, [fp, #-16]
arm 平台跟 mips 和 x86 有比较大的差别
LDRB    指令从value 与basereg 将一个字节加载到dest

当然,正如网友说的,
根本原因如下:
%x是无符号整数的16进制,是无符号!而你的printf传递的实际是字符型,于是有一个类型提升的问题。p是无符号数,那么0xff提升为无符号整数仍然是0xff,而p1是有符号的,0xff实际的值是-1.那么对应的无符号整数仍然应该为-1的对应值,也就是0xffffffff。这才是根本原因。
其实对于这个问题根本不需要使用反汇编。C语言基础就解决了!

printf 要打印一个%x的话,要传递一个4字节的数据,而对于singed 和unsigned char 的处理来说将一个char 转化成一个4字节的数据 在x86 平台上有movsbl、movzbl 区别的对待有符号和无符号的数据,但是对于arm 来说,编译器通过Ldr只把一个字节的数据传递到参数里面就行,这个是由于编译器的不同而不同的。我只是想看一下,对于有符号和无符号的数据处理,编译器到底是怎么处理的?为什么要照搬教条性的东西呢?如果按照教条性的东西,为什么有的平台打印会不同呢?


阅读(22989) | 评论(8) | 转发(1) |
1

上一篇:linux 性能分析

下一篇:rpm知识

给主人留下些什么吧!~~

GFree_Wind2011-05-06 11:41:23

zhangyd6: 呵呵,我只是好奇一下,编译器下面对于有符号和无符号到底是怎么处理的.对于类型提升,到底是怎么进行类型提升的,俺想看看具体的汇编代码。blog 是烂笔头,只是.....
呵呵,抱歉。我理解错了。希望你不要介意。只是讨论问题

zhangyd62011-05-06 11:22:12

GFree_Wind: 说实话,楼主你找错原因了。根本原因不是这个。
根本原因如下:
%x是无符号整数的16进制,是无符号!而你的printf传递的实际是字符型,于是有一个类型提升的问题.....
呵呵,我只是好奇一下,编译器下面对于有符号和无符号到底是怎么处理的.对于类型提升,到底是怎么进行类型提升的,俺想看看具体的汇编代码。blog 是烂笔头,只是记录一下给自己看的。 并不是想证明什么。

GFree_Wind2011-05-05 21:56:25

说实话,楼主你找错原因了。根本原因不是这个。
根本原因如下:
%x是无符号整数的16进制,是无符号!而你的printf传递的实际是字符型,于是有一个类型提升的问题。p是无符号数,那么0xff提升为无符号整数仍然是0xff,而p1是有符号的,0xff实际的值是-1.那么对应的无符号整数仍然应该为-1的对应值,也就是0xffffffff。这才是根本原因。

其实对于这个问题根本不需要使用反汇编。C语言基础就解决了!