堆栈上的结构(ANSI C)

时间:2010-10-04 14:00:45

标签: c memory 64-bit stack

开始研究Ulrich Dreppers“每个程序员应该了解的关于记忆的内容”[1]系列我试图重现

部分中提供的示例时遇到困难

3.3.2缓存效果的测量

据我所知,应该在堆栈上分配结构,因为它们一个接一个地存储在内存中。用小程序验证:

#include <stdio.h>
#include <stdlib.h>

#define NUMPAD 0

struct listelement
{ 
    struct listelement *next;
    long int padding[NUMPAD];
};

typedef struct listelement elem;

int main()
{
    int size_elem = sizeof(elem);
    printf("Size of a list elem: %i\n", size_elem);

    elem _1, _2, _3;

    _1.next = &_2;
    _2.next = &_3;
    _3.next = &_1;

    elem *first, *last, *curr;

    first = &_1;
    last = &_3;
    curr = &_1;

    int k=0;

    while(1)
    {
        printf("Element at %p", curr);
        for (int i=0; i<NUMPAD; i++)
        {
            (curr->padding)[i] = i+k;
            printf("%ld ", (curr->padding)[i]);
        }
        printf("\n");
        if (curr == last)
            break;
        k++;
        curr = curr->next;
    }

    return 0;
}

运行程序时输出为:

Size of a list elem: 8
Element at 0x7fff5fbff540
Element at 0x7fff5fbff530
Element at 0x7fff5fbff520

内存地址之间的差异是16为什么不是8?当增加NUMPAD时,差异似乎会增长得更多,例如对于NUMPAD = 2,我得到的差异为511.

我在运行OSX 10.6 64bit的macbook pro上进行了测试。

[1] http://lwn.net/Articles/252125/

更新:我还使用递增/递减指针。它似乎在32位模式下工作,但在64位模式下不工作。添加代码

first--;
printf("first-- %p\n", first);
if (first == &_2) {
    printf("Decrementing works.\n");
}

macbook:blah nils$ gcc -m32 -DNUMPAD=0 -g -std=c99 -o blah blah.c && ./blah
Size of a list elem: 4
Element at 0xbffff5b8
Element at 0xbffff5b4
Element at 0xbffff5b0
first-- 0xbffff5b4
Decrementing works.
macbook:blah nils$ gcc -DNUMPAD=0 -g -std=c99 -o blah blah.c && ./blah
Size of a list elem: 8
Element at 0x7fff5fbff530
Element at 0x7fff5fbff520
Element at 0x7fff5fbff510
first-- 0x7fff5fbff528

我想知道这是否有意义......也许我应该将所有结构放入数组中。

4 个答案:

答案 0 :(得分:2)

强制警告:一般来说,你不应该对自变量的内存中的相对位置做出任何假设(即,未​​包含在数组或结构中的那些变量)。允许编译器在其认为合适时在堆栈上布置变量,这取决于struct成员的对齐限制。

那就是说,如果你改变的话,我想你会发现:

printf("Element at %p", curr)

printf("Element at %p\n", curr)

你的输出会更有意义。

答案 1 :(得分:1)

请阅读:

http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Zero-Length.html

我怀疑[0]默认为[],如果使用C99进行编译,则大小为0

答案 2 :(得分:0)

零长度数组调用未定义的行为,所以你很幸运它没有编译到system("rm -rf /"); ......

答案 3 :(得分:0)

更改

printf("%ld ", (curr->padding)[i]);

printf("\t%ld ", (curr->padding)[i]);

然后再试一次 - 明白了吗?

以下是我的结果(在32位计算机上),其中包含NUMPAD的各种值。

test $ gcc -std=c99 -DNUMPAD=0 test.c && ./a.out 
Size of a list elem: 4
Element at 0xbfd84df8
Element at 0xbfd84df4
Element at 0xbfd84df0
test $ gcc -std=c99 -DNUMPAD=1 test.c && ./a.out 
Size of a list elem: 8
Element at 0xbff7eff4   0 
Element at 0xbff7efec   1 
Element at 0xbff7efe4   2 
test $ gcc -std=c99 -DNUMPAD=2 test.c && ./a.out 
Size of a list elem: 12
Element at 0xbf9ea260   0   1 
Element at 0xbf9ea254   1   2 
Element at 0xbf9ea248   2   3