在我上一个个人 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数组?
答案 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
}
顺便说一句,指针s1
和s2
应该相同。编译器能够优化相同的字符串并仅存储一次。