在内存中保存变量,C ++

时间:2010-04-02 16:57:53

标签: c string arrays

今天我想到了一些奇怪的事情。当我想用旧的方式在C(C ++)中保存一些字符串时,不使用字符串头,我只是创建数组并将该字符串存储到其中。但是,我读到在本地功能范围内C中的任何变量定义最终都会将这些值推送到堆栈中。

因此,字符串实际上比需要的大2 *。因为首先,推送指令位于存储器中,但是当它们被执行(推入堆栈)时,创建了字符串的另一个“副本”。首先是推送指令,而不是堆栈空间用于一个字符串。

那么,为什么会这样呢?为什么编译器只是将字符串(或其他变量)添加到程序中而不是在执行时再次创建它们?是的,我知道你不能只在程序块中有一些数据,但它可能只是附加到程序的末尾,之前有一些跳转指令。而且,我们只是指出这些数据?因为它们在执行程序时存储在RAM中。

感谢。

4 个答案:

答案 0 :(得分:5)

在C和C ++中有几种处理静态字符串的方法:

char string[] = "Contents of the string";
char const *string2 = "Contents of another string";

如果你在一个函数中执行这些操作,第一个在堆栈上创建一个字符串,就像你描述的那样。第二个只是创建一个指向嵌入到可执行文件中的静态字符串的指针,就像你暗示你想要的一样。

答案 1 :(得分:1)

确实是一个非常好的问题。你知道在变量(定义)上使用static关键字EDIT:声明就是你所描述的,对吗?

就本地人而言,性能优化是关键。无法在函数范围之外访问局部变量。为什么编译器会尝试在堆栈外部为它保留内存?

答案 2 :(得分:1)

它不是如何运作的。没有任何东西被“推”,编译器只是在堆栈框架中保留空间。你不能从函数返回这样的字符串,你将返回一个指向死栈帧的指针。任何后续函数调用都会破坏字符串。

通过让调用者传递一个指向缓冲区的指针来返回字符串,以及一个说明缓冲区有多大的参数,这样当字符串太长时你就不会溢出缓冲区的末尾。

答案 3 :(得分:0)

如果你有:

extern void some_function(char * s, int l);

void do_it(void) {
     char str[] = "I'm doing it!";
     some_function(str, sizeof(str) );
}

这会变成类似的东西(在psudo asm中为制作处理器):

.data
local .do_it.str       ; The contents of str are stored in a static variable
.text   ; text is where code lives within the executable or object file
do_it:
    subtract (sizeof(str)) from stack_pointer        ; This reserves the space for str, sizeof(str)
                                                     ; and a pointer to str on the stack

    copy (sizeof(str)) bytes from .do_it.str to [stack_pointer+0]   ; this loads the local variable
                                               ; using to the memory at the top of the stack
                                               ; This copy can be a function call or inline code.

    push sizeof(str)         ; push second argument first
    push stack_pointer+4     ; assuming that we have 4 byte integers,
                             ; this is the memory just on the other side of where we pushed
                             ; sizeof(str), which is where str[0] ended up

    call some_function

    add (sizeof(str)+8) to stack_pointer          ; reclaim the memory used by str, sizeof(str),
                                                  ; and the pointer to str from the stack
    return

由此可以看出,关于如何创建局部变量str的假设并不完全正确,但这仍然不一定有效。

如果你做了

void do_it(void) {
     static str[] = "I'm doing it!";

然后编译器不会为堆栈保留堆栈上的空间,然后将其复制到堆栈中。如果some_function要改变str的内容,则对do_it的下一个(或同时)调用(在同一个过程中)将使用str的更改版本。

如果some_function被声明为:

extern void some_function(const char * s, int l);

然后,由于编译器可以看到在str内没有更改do_it的操作,即使未声明str,它也可以在堆栈上不生成str的本地副本static