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

问题描述

我有一个用C语言编写的函数,其中包含一个像这样的指针变量

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

void main()
{
    print();
    print();
}

如果我两次调用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作为局部变量是免费的。

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

因此,您的print函数本质上尽可能便宜—它根本不执行任何实际分配。

,

您可以将代码粘贴到compiler explorer上以查看会发生什么。从您的代码中,这是生成的附生者:

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,1
        call    fwrite
        mov     rcx,1
        call    fwrite
        xor     eax,eax
        pop     rcx
        ret
.L.str:
        .asciz  "hello world"

重要的部分在最后:

.L.str:
        .asciz  "hello world"

"hello world"仅像全局变量一样在此处声明,并在每次调用函数print时使用。

就像您这样声明一样:

#include<stdio.h>

const char* hello = "hello world";

void print()
{
    fprintf(stdout,hello);
}

void main()
{
    print();
    print();
}

在这种情况下,编译器看到了优化并完成了优化。但是,我不能肯定会一直这样,因为它不能依赖于编译器。

,
  1. <div class="alert alert-warning mt-2" id="mainArea"> {% for question in testing %} <div class="alert alert-secondary mt-2" id="questionArea{{ forloop.counter0 }}"> <form method="post" id='testForm' data-url="{% url 'test' %}"> {% csrf_token %} <table> <thead> <tr> <th>{{ forloop.counter }}. {{ question.1 }}</th> </tr> </thead> </table> {% if question.4 %} {% for images in img %} {% if images.picture == question.4 %} <img src="{{ images.picture.url }}" class="mainImg" alt=""><br> {% endif %} {% endfor %} {% endif %} {% if question.0 == '1' %} {% for el in question.2 %} <label> <input type="checkbox" class="checkbox" onclick="getCheckedCheckBoxes()" name="{{ question.1 }}" value="{{ el }}" id="{{ question.1 }}"/> {{ el }} </label><br> {% endfor %} {% else %} <label> {% for num in question.2 %} <h6>{{ forloop.counter }}. </h6> <select id="myselect" class="myselect" name="myselect" onchange="getSequence()"> <option disabled selected></option> {% for el in question.2 %} <option value="{{ el }}" id="{{ question.1 }}{{ forloop.counter0 }}" label="{{ el }}"> </option> {% endfor %} </select><br> {% endfor %} </label> {% endif %} </form> </div> {% endfor %} <button type="button" value="snd" id="sendAnsButton" onclick="sendAnswers()" class="button">Завершить тест</button> </div> 变量

当函数退出时,自动变量将终止其寿命。因此,仅当您位于函数内部时,才会在堆栈上分配内存。函数存在时将释放它。

  1. 字符串文字具有程序寿命,并且位于存储文字的位置(通常是.rodata段)。在程序构建过程中会填充此区域,它在内存中的实际表示方式取决于实现方式

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...