使用#define值作为C中的函数参数 - 为什么它可以工作?

时间:2016-12-31 19:34:42

标签: c file fopen

在我上一个个人 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数组?

1 个答案:

答案 0 :(得分: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应该相同。编译器能够优化相同的字符串并仅存储一次。