web-dev-qa-db-fra.com

Pourquoi un long int prend-il 12 octets sur certaines machines?

J'ai remarqué quelque chose d'étrange après avoir compilé ce code sur ma machine:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");

    int a,b,c,d;

    int e,f,g;

    long int h;

    printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
        &a,&b,&c,&d,&e,&f,&g,&h);

    return 0;
}

Le résultat est le suivant. Notez qu'entre chaque adresse int il y a une différence de 4 octets. Cependant, entre le dernier entier et le long entier, il y a une différence de 12 octets:

 Hello, World!
 The addresses are:

 da54dcac 
 da54dca8 
 da54dca4 
 da54dca0 
 da54dc9c 
 da54dc98 
 da54dc94 
 da54dc88
26
yoyo_fun

Cela n'a pas pris 12 octets, il n'en a fallu que 8. Cependant, la valeur par défaut alignement pour un entier de 8 octets sur cette plate-forme est de 8 octets. En tant que tel, le compilateur devait déplacer le long int vers une adresse qui est divisible par 8. L'adresse "évidente", da54dc8c, n'est pas divisible par 8 d'où l'écart de 12 octets.

Vous devriez pouvoir tester cela. Si vous ajoutez un autre entier avant le long, donc il y en a 8, vous devriez trouver que le long entier sera bien aligné sans bouger. Ce ne sera plus que 8 octets à partir de l'adresse précédente.

Il vaut probablement la peine de souligner que, bien que ce test devrait fonctionner, vous ne devez pas vous fier aux variables organisées de cette façon. Un compilateur C est autorisé à faire toutes sortes de choses géniales pour essayer de faire fonctionner votre programme rapidement, y compris en réorganisant les variables (avec quelques mises en garde).

81
Alex

En effet, votre compilateur génère un remplissage supplémentaire entre les variables pour garantir qu'elles sont correctement alignées en mémoire.

Sur la plupart des processeurs modernes, si une valeur a une adresse qui est un multiple de sa taille, il est plus efficace d'y accéder. S'il avait mis h au premier emplacement disponible, son adresse aurait été 0xda54dc8c, qui n'est pas un multiple de 8, donc aurait été moins efficace à utiliser. Le compilateur le sait et ajoute un peu d'espace inutilisé entre vos deux dernières variables afin de s'assurer que cela se produit.

9
Jules

Votre test ne teste pas nécessairement ce que vous pensez qu'il est, car il n'y a aucune exigence de la langue pour relier l'adresse de l'une de ces variables locales les unes aux autres.

Vous devez les placer sous forme de champs dans une structure afin de pouvoir déduire quelque chose sur l'allocation de stockage.

Les variables locales ne sont pas tenues de partager le stockage côte à côte d'une manière particulière. Le compilateur peut insérer une variable temporaire n'importe où dans la pile, par exemple, qui pourrait se trouver entre deux de ces variables locales.

En revanche, il ne serait pas permis d'insérer une variable temporaire dans une structure, donc si vous imprimiez les adresses des champs de structure à la place, vous compareriez les éléments prévus alloués à partir du même mandrin logique de mémoire (la structure).

2
Erik Eidt