Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果一个C函数被调用两次,它会创建一个在函数中声明的变量两次吗?_C_Printf_Dynamic Memory Allocation_Stdio - Fatal编程技术网

如果一个C函数被调用两次,它会创建一个在函数中声明的变量两次吗?

如果一个C函数被调用两次,它会创建一个在函数中声明的变量两次吗?,c,printf,dynamic-memory-allocation,stdio,C,Printf,Dynamic Memory Allocation,Stdio,我有一个用C写的函数,它由如下指针变量组成 #include<stdio.h> void print() { char *hello="hello world"; fprintf(stdout,"%s",hello); } void main() { print(); print(); } #包括 作废打印() { char*hello=“hello world”; fprintf(标准输出,“%s”,您好)

我有一个用C写的函数,它由如下指针变量组成

#include<stdio.h>
void print()
{
    char *hello="hello world";
    fprintf(stdout,"%s",hello);
}

void main()
{
    print();
    print();
}
#包括
作废打印()
{
char*hello=“hello world”;
fprintf(标准输出,“%s”,您好);
}
void main()
{
打印();
打印();
}
如果我调用print()函数两次,它会为hello变量分配两次内存吗

如果我调用print()函数两次,它会为hello变量分配两次内存吗

不,它是一个字符串文本,只分配一次

您可以通过检查地址来检查:

fprintf(stdout,"%p: %s\n", hello, hello);
样本输出:

0x563b972277c4: hello world
0x563b972277c4: hello world
如果我调用print()函数两次,它会为hello变量分配两次内存吗

对。但是,
hello
是一个指针,在64位机器上占用8字节的堆栈空间。成本实际上是无法衡量的。此外,编译器根本不需要分配变量,因为您从未尝试获取其地址。编译器可以自由地将代码有效地转换为:

void print()
{
    fprintf(stdout, "%s", "hello world");
}
这意味着
hello
的声明在运行时不会导致任何内存分配。并非出于所有目的,将
hello
作为局部变量是免费的

相反,在应用程序的数据段中,以零结尾的字符串文字“helloworld”只分配一次。编译器可以这样做,因为它知道C字符串文本是只读的,所以不允许修改它。此外,在运行时不执行动态内存分配。字符串文本的内存是静态分配的,其生存期是应用程序的生存期

因此,您的
print
功能基本上是尽可能便宜的-它根本不执行任何实际分配。

您可以将代码粘贴到以查看发生了什么。根据您的代码,这是生成的assebler:

print():                              # @print()
        mov     rcx, qword ptr [rip + stdout]
        mov     edi, offset .L.str
        mov     esi, 11
        mov     edx, 1
        jmp     fwrite                  # TAILCALL
main:                                   # @main
        push    rax
        mov     rcx, qword ptr [rip + stdout]
        mov     edi, offset .L.str
        mov     esi, 11
        mov     edx, 1
        call    fwrite
        mov     rcx, qword ptr [rip + stdout]
        mov     edi, offset .L.str
        mov     esi, 11
        mov     edx, 1
        call    fwrite
        xor     eax, eax
        pop     rcx
        ret
.L.str:
        .asciz  "hello world"
重要的部分在最后:

.L.str:
        .asciz  "hello world"
“hello world”
仅在此处声明,就像一个全局变量一样,每次调用函数
print
时都会使用它

就像你这样声明:

#包括
const char*hello=“hello world”;
作废打印()
{
fprintf(标准输出,“%s”,您好);
}
void main()
{
打印();
打印();
}
在本例中,编译器看到了优化并进行了优化。但是,我不能肯定这种情况会一直发生,因为它不能依赖于编译器

  • hello
    变量
  • 自动变量在函数退出时结束其生命周期。因此,只有在函数内部时,才会在堆栈上分配内存。当函数存在时,它将被释放

  • 字符串文字具有程序生存期,并且是存储文字的地方(通常是.rodata段)。该区域在程序构建期间填充,它在内存中的实际表示方式取决于实现

  • 这取决于hello变量的内存。您是指用于字符串数据(“hello world”)的内存,还是用于变量本身的内存(将存储该数据的地址)?我是指存储字符串所需的总空间,该空间很可能由实现定义。大多数现代系统将为(常量)字符串文字数据创建空间,并在编译时初始化该数据。但他们没有义务这样做。(我想)是的,会的。但我认为这取决于编译器。将变量声明为全局变量只会占用空间1对吗?@selstingeorge字符串是全局的。编译器并不愚蠢,他们知道在这里分配多个字符串是不必要的。