c - 32 位机器如何处理大于 2^32 的数字?

标签 c gcc x86 32-bit

我试图了解涉及大于 232 的数字的计算如何在 32 位计算机上发生。

C代码

$ cat size.c
#include<stdio.h>
#include<math.h>

int main() {

    printf ("max unsigned long long = %llu\n",
    (unsigned long long)(pow(2, 64) - 1));
}
$

gcc 输出

$ gcc size.c -o size
$ ./size
max unsigned long long = 18446744073709551615
$

对应的汇编代码

$ gcc -S size.c -O3
$ cat size.s
    .file   "size.c"
    .section    .rodata.str1.4,"aMS",@progbits,1
    .align 4
.LC0:
    .string "max unsigned long long = %llu\n"
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $-1, 8(%esp)   #1
    movl    $-1, 12(%esp)  #2
    movl    $.LC0, 4(%esp) #3
    movl    $1, (%esp)     #4
    call    __printf_chk
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
$

第 1 - 4 行到底发生了什么?

这是汇编级别的某种字符串连接吗?

最佳答案

__printf_chkprintf 的包装器,它检查堆栈溢出,并采用额外的第一个参数,一个标志(例如,参见 here 。)

pow(2, 64) - 1 已优化为 0xffffffffffffffff,因为参数是常量。

按照通常的调用约定,__printf_chk() 的第一个参数(int flag)是堆栈上的一个 32 位值(位于 % espcall 指令时)。下一个参数 const char * format 是一个 32 位指针(堆栈上的下一个 32 位字,即 %esp+4)。并且正在打印的 64 位数量占用接下来的两个 32 位字(在 %esp+8%esp+12):

pushl   %ebp                 ; prologue
movl    %esp, %ebp           ; prologue
andl    $-16, %esp           ; align stack pointer
subl    $16, %esp            ; reserve bytes for stack frame
movl    $-1, 8(%esp)   #1    ; store low half of 64-bit argument (a constant) to stack
movl    $-1, 12(%esp)  #2    ; store high half of 64-bit argument (a constant) to stack
movl    $.LC0, 4(%esp) #3    ; store address of format string to stack
movl    $1, (%esp)     #4    ; store "flag" argument to __printf_chk to stack
call    __printf_chk         ; call routine
leave                        ; epilogue
ret                          ; epilogue

编译器有效地重写了这个:

printf("max unsigned long long = %llu\n", (unsigned long long)(pow(2, 64) - 1));

...进入这个:

__printf_chk(1, "max unsigned long long = %llu\n", 0xffffffffffffffffULL);

...并且在运行时,调用的堆栈布局如下所示(将堆栈显示为 32 位字,地址从图表底部向上递增):

        :                 :
        :     Stack       :
        :                 :
        +-----------------+
%esp+12 |      0xffffffff | \ 
        +-----------------+  } <-------------------------------------.
%esp+8  |      0xffffffff | /                                        |
        +-----------------+                                          |
%esp+4  |address of string| <---------------.                        |
        +-----------------+                 |                        |
%esp    |               1 | <--.            |                        |
        +-----------------+    |            |                        |
                  __printf_chk(1, "max unsigned long long = %llu\n", |
                                                    0xffffffffffffffffULL);

关于c - 32 位机器如何处理大于 2^32 的数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3897906/

相关文章:

gcc - 使用 -isystem 包含 CMake 项目依赖项包含目录

c - 内联汇编器: Pass a constant

assembly - 为什么 x86 汇编中一个字是 2 个字节而不是 4 个字节?

x86 - AVX2,如何有效地将四个整数加载到 256 位寄存器的偶数索引并复制到奇数索引?

c - 使用 gcc 编译基本 x86 代码时出现链接错误

c - 使用 make 文件在 c 中的单独目录中生成输出文件

c - 可变函数的问题

c - 局部变量在栈上的地址

c++ - 插入排序错误

c++ - C++ 中的 Win32 显示中文...我做错了什么?