以下内容解答三个问题:
- 对一个
unsigned char
取负, 结果会是什么? sizeof()
如何计算?- (静态)数组保存在哪里?
1. 问题1
使用编译器: "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
CPU信息: AMD A10 PRO-7800B R7
使用 32 位操作系统
编译选项: $GCC -O0 -S
#include <stdlib.h>
#include <stdio.h>
typedef unsigned char uchar;
int main() {
uchar a=0xff, b=0x01, c;
b = b << 4;
c = -(a&b);
printf("%d", c);
return 0;
}
.file "test.c"
.section .rodata
.LC0:
.string "%d"
.text
.globl main
.type main, @function
main:
pushl %ebp ;
movl %esp, %ebp ;
andl $-16, %esp ;
subl $32, %esp ; 32 位栈空间
movb $-1, 31(%esp) ; 31(%esp) = -1 // -1 的补码(32bit)是 0xFFFFFFFF, 低八位赋值给a正好是 0xff
movb $1, 30(%esp) ; 30(%esp) = 1 // 30(%esp)是变量 b
salb $4, 30(%esp) ; 30(%esp) = 4 // b <<= 4
movzbl 30(%esp), %eax ; 高位零填充 b // b在此变为 32 位有符号
movzbl 31(%esp), %edx ; 高位零填充 a // a在此变为 32 位有符号
andl %edx, %eax ; b = b & a
negl %eax ; b 取负数 (补码负数) // b 为32位有符号
movb %al, 29(%esp) ; b 取低八位 // 这里就是 c 的值
movzbl 29(%esp), %edx ; 高位零填充, 准备打印的数据
movl $.LC0, %eax ;
movl %edx, 4(%esp) ;
movl %eax, (%esp) ;
call printf ;
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",@progbits
2. 问题2
使用编译器: "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
CPU信息: AMD A10 PRO-7800B R7
使用 32 位操作系统
编译选项: $GCC -O0 -S
#include <stdlib.h>
#include <stdio.h>
typedef unsigned char uchar;
int main() {
uchar *str="abcxyz", *cha, str2[]="abcxyz";
uchar arr[] = {'i', 'j', 'k', 'l', 'm', 'n', 0};
cha = arr;
printf("%d\n", sizeof(str)); // 4
printf("%d\n", sizeof(str2)); // 7
printf("%d\n", sizeof(arr)); // 7
printf("%d\n", sizeof(cha)); // 4
printf("%c\n", arr[2]);
printf("%s\n", arr);
return 0;
}
.file "test2.c"
.section .rodata
.LC0:
.string "abcxyz"
.LC1:
.string "%d\n"
.LC2:
.string "%c\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $48, %esp ; 栈空间48字节
movl $.LC0, 44(%esp) ; 赋值字符串 abcxyz // 44(%esp)是 数组str2, 占用栈空间7字节
movl $2019779169, 33(%esp) ; 33(%esp) 是
movw $31353, 37(%esp) ; 37(%esp) 是
movb $0, 39(%esp) ; 39(%esp) 是
movb $105, 26(%esp) ; 数组赋值 'i' // 26(%esp) 是 数组arr的头
movb $106, 27(%esp) ; 'j'
movb $107, 28(%esp) ; 'k'
movb $108, 29(%esp) ; 'l'
movb $109, 30(%esp) ; 'm'
movb $110, 31(%esp) ; 'n'
movb $0, 32(%esp) ; '\0'
leal 26(%esp), %eax ; %eax = arr
movl %eax, 40(%esp) ; 40(%esp) = arr
movl $.LC1, %eax ; %eax = "%d\n" //
movl $4, 4(%esp) ; 4(%esp) = 4 // 由此可见, sizeof()由编译器自动执行
movl %eax, (%esp) ; %esp = "%d\n" // 但是在64位机中, 这里的传参应该是用寄存器 (%edi) 和 (%esi) 完成才对, 这里是32位机, 看起来好像是用了栈内存
call printf ; printf
movl $.LC1, %eax ; %eax = "%d\n" //
movl $7, 4(%esp) ; 4(%esp) = 7 // 由此可见, sizeof()由编译器自动执行
movl %eax, (%esp) ; %esp = %eax
call printf
movl $.LC1, %eax
movl $7, 4(%esp)
movl %eax, (%esp)
call printf
movl $.LC1, %eax
movl $4, 4(%esp)
movl %eax, (%esp)
call printf ; 下面是数组取值与打印
movzbl 28(%esp), %eax ;
movzbl %al, %edx ;
movl $.LC2, %eax ;
movl %edx, 4(%esp) ; 栈内存的"第二个" 32 位空间为第二个参数
movl %eax, (%esp) ; 栈内存顶为第一个参数
call printf ; 下面是打印字符串 "%s"
leal 26(%esp), %eax ;
movl %eax, (%esp) ;
call puts ; 竟然是调用了 puts 函数
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",@progbits
3. 问题3
同问题二