2016-12-31 32 views
-2

在我上個人的C項目中,我玩過一些文件。我試過的一件事是將#define值作爲參數。最後是一段代碼,以便你知道我的意思。在C中使用#define值作爲函數參數 - 它爲什麼會起作用?

我的問題是:爲什麼它的工作?數據在哪裏存儲?它是否符合ANSI C?

#include <stdio.h> 
#define FILE_NAME "test.txt" 

void open_file(FILE**, char*); 

int main(int argc, char *argv[]) 
{ 
    FILE* file; 
    open_file(&file, FILE_NAME); 
    return 0; 
} 

void open_file(FILE** file, char* filename) 
{ 
    *(file)=fopen(filename, "r"); 
} 

爲什麼我可以使用文本作爲參數而不是char數組,其中的文件名被存儲?

+4

我不明白這個問題。你定義了一個被預處理器替代的宏,所以你的調用實際上是'open_file(&file,「test.txt」);' - 你不想讓它工作嗎? – UnholySheep

+0

預期的行爲是什麼?什麼是實際行爲? – merlin2011

+0

一切都很好。我希望它以這種方式工作,但我想知道爲什麼我可以有一個字符串作爲參數,而不是包含文件名的字符數組。我也想知道字符串的存儲位置(堆棧也許?)。最後是這種類型的參數符合ANSI-C嗎? – AceOmn

回答

5

預處理器將您的代碼擴展爲open_file(&file, "test.txt");

"test.txt"是一個字符串文字。編譯器將其嵌入到二進制可執行文件中。當你加載你的程序時它被加載到內存中。

我們來分析一下這個簡單的例子:

#include <stdio.h> 

int main(int argc, char **argv) { 
     printf("hello, wolrd!\n"); 
     return 0; 
} 

我們可以爲生成彙編:gcc -S hello.c

 .file "hello.c" 
     .section  .rodata 
.LC0: 
     .string "hello, wolrd!" 
     .text 
     .globl main 
     .type main, @function 
main: 
.LFB0: 
     .cfi_startproc 
     pushq %rbp 
     .cfi_def_cfa_offset 16 
     .cfi_offset 6, -16 
     movq %rsp, %rbp 
     .cfi_def_cfa_register 6 
     subq $16, %rsp 
     movl %edi, -4(%rbp) 
     movq %rsi, -16(%rbp) 
     movl $.LC0, %edi 
     call puts 
     movl $0, %eax 
     leave 
     .cfi_def_cfa 7, 8 
     ret 
     .cfi_endproc 
.LFE0: 
     .size main, .-main 
     .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609" 
     .section  .note.GNU-stack,"",@progbits 

正如你所看到的,字符串被放置在.rodata - 只讀數據部分。您可以獲取該字符串的內存地址,並嘗試訪問它:

#include <stdio.h> 

int main(int argc, char **argv) { 
     const char *s1 = "hello, world!\n"; // both strings are identical 
     char *s2 = "hello, world!\n"; 
     printf(s1); // Read-only access - OK 
     s2[0] = 'x'; // Write to .rodata - SEGFAULT (crash) here 
     return 0; // we never reach here 
} 

順便說一下,指針s1s2應該是相同的。編譯器能夠優化相同的字符串並只存儲一次。

+0

thx,那就是我想知道的。所以它存儲在內存中,但我沒有varname名稱來訪問它,除非我聲明一個pionter並初始化它爲這個字符串。 – AceOmn

+0

沒問題。現在有趣的是,該字符串是隻讀的,但可以使用指向非常量字符串的指針來訪問它,從而觸發崩潰。這是使用's2'字符串顯示的。這不是一個bug,它是C語言的一個特性。有人開玩笑說C是「高層次集會」 - 你可以看到爲什麼。 – ezaquarii

+1

鏈接到[相關參考](http://en.cppreference.com/w/c/language/string_literal)以獲取更多關於字符串文字的信息(只爲完成) – UnholySheep

相關問題