gpt4 book ai didi

c - 字符串文字的全局变量与宏扩展

转载 作者:行者123 更新时间:2023-12-04 12:26:48 26 4
gpt4 key购买 nike

我试图了解预处理器和 的一些复杂之处。 C 编译器(特别是 gnu gcc)和字符串文字。与使用 #define 相比,为仅在内存中占据一个位置的字符串文字分配全局变量是否更有效?预处理程序指令?

在本例中,字符串文字位于内存中并多次访问:

#include <stdio.h>
#include <string.h>
char OUTPUT[20] = "Hello, world!!!";
int main (){
printf("%s is %d characters long.\n", OUTPUT, strlen(OUTPUT));
return 0;
}

与使用预处理器进行对比:
#include <stdio.h>
#include <string.h>
#define OUTPUT "Hello, world!!!"

int main (){
printf("%s is %d characters long.\n", OUTPUT, (int) strlen(OUTPUT));
return 0;
}

翻译成:
#include <stdio.h>
#include <string.h>
#define OUTPUT "Hello, world!!!"

int main (){
printf("%s is %d characters long.\n", "Hello, world!!!", (int) strlen("Hello, world!!!"));
return 0;
}

我真正要问的是在使用预处理器的最后两个示例中,编译器是否有两个单独的“Hello, world!!!”实例。在两个单独的内存位置中,还是编译器足够聪明以使其成为一个内存位置?

如果是两个独立的内存位置,那么对程序常量使用全局变量而不是宏扩展不是更资源友好吗?

最佳答案

您的编译器应该足够智能以存储字符串的一个实例。您可以通过检查程序的汇编输出来验证这一点。

例如,使用 GCC:

假设您的第一个示例称为“global.c”。

gcc -Wall -S global.c

.file "global.c"
.globl OUTPUT
.data
.align 16
.type OUTPUT, @object
.size OUTPUT, 20
OUTPUT:
.string "Hello, world!!!"
.zero 4
.section .rodata
.LC0:
.string "%s is %d characters long.\n"
.text
.globl main
.type main, @function
main:
// More code...

假设您的预处理器示例称为“preproc.c”。
gcc -Wall -S preproc.c
.file "preproc.c"
.section .rodata
.LC0:
.string "%s is %d characters long.\n"
.LC1:
.string "Hello, world!!!"
.text
.globl main
.type main, @function
main:
// More code...

在这两种情况下,只有一份“Hello, world!!!”并且“%s 是 %d 个字符长。\n”存在。在第一个示例中,您必须为 20 个字符节省空间,因为您的代码有一个可修改的数组。如果你改变了这个
char OUTPUT[20] = "Hello, world!!!";


const char * const OUTPUT = "Hello, world!!!";

你会得到:
.file   "global.c"
.globl OUTPUT
.section .rodata
.LC0:
.string "Hello, world!!!"
.align 8
.type OUTPUT, @object
.size OUTPUT, 8
OUTPUT:
.quad .LC0
.LC1:
.string "%s is %d characters long.\n"
.text
.globl main
.type main, @function
main:
// More code...

现在您正在为指针和字符串节省空间。

在这种情况下,哪种方式更好可以忽略不计,但我建议使用预处理器,以便您的字符串范围保持在主函数内。

两者都发出几乎相同的优化代码。

Global.c 与 ( const char * const OUTPUT ):
gcc -Wall -O3 -S global.c

.file "global.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!!!"
.LC1:
.string "%s is %d characters long.\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB44:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $15, %ecx
movl $.LC0, %edx
movl $.LC1, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE44:
.size main, .-main
.globl OUTPUT
.section .rodata
.align 8
.type OUTPUT, @object
.size OUTPUT, 8
OUTPUT:
.quad .LC0
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits

预处理程序
gcc -Wall -O3 -S preproc.c

.file "preproc.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!!!"
.LC1:
.string "%s is %d characters long.\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB44:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $15, %ecx
movl $.LC0, %edx
movl $.LC1, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE44:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits

查看两者 main功能,你可以看到指令是相同的。

关于c - 字符串文字的全局变量与宏扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16630822/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com