是否printf
佔據堆棧存儲器?的printf在C不佔用內存?
printf("Hello world");
"Hello world"
是否有固定地址?
請幫我理解。
編輯:
是我們傳遞了printf
被存儲在本地指針變量的參數。 如果我使用數組來存儲50個字符串文字,它會佔用堆棧內存,但是如果使用了printf
,它不會佔用內存 - 這正是我所聽到的。但我不知道怎麼printf
沒有考慮內存作爲我們聲明的數組。
請幫我理解!
是否printf
佔據堆棧存儲器?的printf在C不佔用內存?
printf("Hello world");
"Hello world"
是否有固定地址?
請幫我理解。
編輯:
是我們傳遞了printf
被存儲在本地指針變量的參數。 如果我使用數組來存儲50個字符串文字,它會佔用堆棧內存,但是如果使用了printf
,它不會佔用內存 - 這正是我所聽到的。但我不知道怎麼printf
沒有考慮內存作爲我們聲明的數組。
請幫我理解!
這取決於你的平臺的調用約定和標準庫是如何實現的。
例如,採取以下程序:
#include <stdio.h>
int main(void)
{
printf("Hello, World\n");
return 0;
}
和下面的命令行編譯它:
gcc -S -std=c99 -pedantic -Wall -Werror syscall.c
在使用gcc 2.96 32位的Red Hat盒(i686的),我們得到以下的機器代碼:
1 .file "syscall.c" 2 .version "01.01" 3 gcc2_compiled.: 4 .section .rodata 5 .LC0: 6 .string "Hello, World\n" 7 .text 8 .align 4 9 .globl main 10 .type main,@function 11 main: 12 pushl %ebp 13 movl %esp, %ebp 14 subl $8, %esp 15 subl $12, %esp 16 pushl $.LC0 17 call printf 18 addl $16, %esp 19 movl $0, %eax 20 leave 21 ret 22 .Lfe1: 23 .size main,.Lfe1-main 24 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"
線16將字符串字面地址壓入堆棧,然後調用printf
。
下面是相同的代碼,已編譯的相同的方式,在64位SLES使用gcc 4.1.2 10盒(x86_64的):
1 .file "syscall.c" 2 .section .rodata 3 .LC0: 4 .string "Hello, World" 5 .text 6 .globl main 7 .type main, @function 8 main: 9 .LFB2: 10 pushq %rbp 11 .LCFI0: 12 movq %rsp, %rbp 13 .LCFI1: 14 movl $.LC0, %edi 15 call puts 16 movl $0, %eax 17 leave 18 ret ;; ;; additional content not included ;;
在這種情況下,線14寫入字符串的地址字面到寄存器(%edi
)代替推送到堆棧上。還要注意,這個版本的gcc足夠聰明地意識到,由於我傳遞了一個類型爲char *
的參數,它可以用puts
來代替一個調用。
無論哪種情況,您在撥打電話時都會創建一個新的堆棧幀;不同之處在於堆棧幀中的內容。在Red Hat框中,它將包含字符串文字的地址;在SLES 10盒上,它不會。
字符串常量,這是什麼"Hello world"
是,佔用內存,而不是在棧中,但在一個只讀的靜態部分。除了read-only memory
之外,其餘的都是實現細節。
這是沒有必要的是相同的字符串文字佔用相同的內存(所以地址不能保證恆定的),但他們可能。
在C語言中,字符串具有靜態存儲時間。這意味着它們在整個程序期間的存在(以及指向它們的指針仍然有效)這與通常在調用幀堆棧上實現的自動局部變量相反。
請注意,雖然字符串不佔用堆棧,但printf是一個函數調用,並會相應地增加堆棧。 –
@WoodrowDouglass我懷疑這一點。 'printf'本身駐留在一個庫中,它也具有靜態持續時間。 –
我並不是說'printf'的代碼在堆棧中,我的意思是'call'指令將返回地址壓入堆棧,因此調用* any * non-inline函數的行爲會增加堆棧。 –