2010-10-04 21 views
4

Après avoir commencé à étudier Ulrich Dreppers « Ce que tout programmeur doit savoir sur la mémoire » série [1] Je suis resté bloqué en essayant de reproduire les exemples présentés dans la sectionStructs sur la pile (ANSI C)

3.3.2 Mesures Pour autant que je sache, les structures doivent être allouées sur la pile puisqu'elles sont en mémoire les unes après les autres. Vérification de cela avec un petit programme:

#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; 
} 

Lors de l'exécution du programme est la sortie:

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

Les différences entre les adresses de mémoire, est cependant 16 pourquoi pas 8? En augmentant NUMPAD la différence semble croître encore plus, par exemple pour NUMPAD = 2 j'obtiens une différence de 511.

J'ai fait les tests sur un macbook pro fonctionnant sous OSX 10.6 64bit.

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

Mise à jour: Je joue aussi avec incrémenter/décrémenter les pointeurs. Il semble fonctionner en mode 32 bits, mais pas en mode 64 bits. Ajouter le code

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 

Je me demande comment cela a du sens ... peut-être que je devrais simplement placer tous les structs dans un tableau.

+0

Essayez de compiler avec des erreurs -pedantic. C'est un code C standard invalide ... Vous pouvez avoir array [] dans struct/union. Mais pas de tableau d'éléments 0. – Nyan

+0

Je sais, mais cela ne semble pas être le problème – Nils

+1

Oui, vous devriez certainement placer les structures dans un tableau si vous avez des attentes qu'ils seront adjacents. Notez que l'article Dreppers lui-même dit "Le programme * crée un tableau * correspondant à la taille de l'ensemble de travail des éléments de ce type" –

Répondre

0

Un tableau de longueur nulle invoque un comportement non défini, de sorte que vous avez de la chance, il ne compile pas à system("rm -rf /"); ...

+0

Même avec NUMPAD = 1, j'ai obtenu la différence 0x7F sur une machine 32 bits. Il est devenu 0x1ff avec NUMPAD = 2 – Amarghosh

+0

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

+0

ce n'est pas à propos des tableaux de longueur nulle - voir ma réponse. @Anders – Amarghosh

2

Avertissement obligatoire: en général, vous ne devriez pas faire d'hypothèses sur la position relative dans la mémoire des variables indépendantes (c'est-à-dire, celles qui ne sont pas wrap ped dans un tableau ou struct). Le compilateur est autorisé à mettre en forme des variables sur la pile comme bon lui semble, sous réserve des restrictions d'alignement des membres de la structure.

Cela dit, je pense que vous constaterez que si vous changez:

printf("Element at %p", curr) 

à

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

Votre sortie fera beaucoup plus de sens.

+0

Est-ce? Aussi pour la pile? Mais les doivent être alignés en mémoire, sinon les tests, qui sont décrits dans 3.3.2 Les mesures de l'effet de cache n'ont aucun sens .. – Nils

+0

Cela semble être la seule bonne réponse. La localisation relative des variables indépendantes est complètement à la mise en œuvre. Bien sûr, l'article de Drepper essayait d'enseigner aux programmeurs le comportement d'une implémentation particulière, il serait donc intéressant de voir pourquoi il y a cette contradiction apparente. –

0

changement

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

à

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

et essayez à nouveau - got it?

Voici mes résultats (sur une machine 32 bits) avec diverses valeurs pour 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 
+0

Thx pour le signaler, j'ai supervisé que j'ai oublié de mettre un espace (ou une tabulation), cependant dans le cas où NUMPAD = 0 il ne change rien. Avez-vous essayé cela sur Linux? – Nils

+0

@Nils Oui, j'ai essayé sur Linux – Amarghosh

+0

Si je compile pour 32bit, les différences entre les adresses sont les mêmes que ci-dessus: Il correspond à la taille de elem, étrange .. – Nils