class Address {
int i ;
char b;
string c;
public:
void showMap ( void ) ;
};
void Address :: showMap ( void ) {
cout << "address of int :" << &i << endl ;
cout << "address of char :" << &b << endl ;
cout << "address of string :" << &c << endl ;
}
La sortie est:
address of int : something
address of char : // nothing, blank area, that is nothing displayed
address of string : something
Pourquoi?
Une autre chose intéressante: si int, char, string est en public, alors la sortie est
... int : something
... char :
... string : something_2
something_2 - something
est toujours égal à 8. Pourquoi? (pas 9)
Lorsque vous prenez l'adresse de b, vous obtenez char *
. operator<<
interprète cela en tant que chaîne C et essaie d'imprimer une séquence de caractères au lieu de son adresse.
essayez plutôt cout << "address of char :" << (void *) &b << endl
.
[EDIT] Comme l'a commenté Tomek, une distribution plus appropriée à utiliser dans ce cas est static_cast
, qui constitue une alternative plus sûre. Voici une version qui l'utilise à la place de la distribution de style C:
cout << "address of char :" << static_cast<void *>(&b) << endl;
Il y a 2 questions:
Les pointeurs d’impression impriment l’adresse pour le int*
et le string*
, mais pas le contenu pour char*
car il existe une surcharge particulière dans operator<<
. Si vous voulez l'adresse alors utilisez: static_cast<const void *>(&c);
int
et string
est-elle 8
sizeof(int)
est 4
sur votre plate-forme et sizeof(char)
est 1
. Vous devriez donc vraiment vous demander pourquoi 8
et non 5
. La raison en est que la chaîne est alignée sur une limite de 4 octets. Les machines fonctionnent avec des mots plutôt que des octets et plus rapidement si les mots ne sont pas "divisés" en quelques octets ici et quelques octets ici. Ceci s'appelle alignement
Votre système est probablement aligné sur des limites de 4 octets. Si vous aviez un système 64 bits avec des entiers 64 bits, la différence serait de 16.
(Remarque: le système 64 bits fait généralement référence à la taille d'un pointeur et non d'un int. Ainsi, un système 64 bits avec un int de 4 octets aurait toujours une différence de 8, 4 = 1 = 5 mais arrondi à 8). Si sizeof (int) est 8 alors 8 + 1 = 9 mais ceci arrondit à 16)
Lorsque vous transmettez en continu l'adresse d'un caractère à un ostream, il l'interprète comme étant l'adresse du premier caractère d'une chaîne ASCIIZ "style C" et tente d'imprimer la chaîne présumée. Vous n'avez pas de terminateur NUL, donc la sortie continuera d'essayer de lire de la mémoire jusqu'à ce qu'il en trouve un ou le système d'exploitation l'arrête pour avoir tenté de lire une adresse invalide. Toutes les ordures analysées seront envoyées à votre sortie.
Vous pouvez probablement le faire afficher l'adresse que vous voulez en le lançant, comme dans (void*)&b
.
Concernant les décalages dans la structure: vous avez observé que la chaîne est placée au décalage 8. Ceci est probablement dû au fait que vous avez des ints de 32 bits, puis un caractère de 8 bits, puis le compilateur choisit d’insérer 3 caractères de plus de 8 bits L'objet de chaîne sera aligné sur une limite de mot de 32 bits. De nombreux processeurs/architectures de mémoire ont besoin de pointeurs, d'intes, etc. pour se situer sur des limites de taille Word afin d'effectuer des opérations efficaces sur eux. Sinon, ils devraient effectuer beaucoup plus d'opérations pour lire et combiner plusieurs valeurs en mémoire avant de pouvoir les utiliser. dans une opération. Selon votre système, il se peut que chaque objet de classe doive commencer par une limite de Word ou que std::string
en particulier commence par un size_t, un pointeur ou un autre type nécessitant un tel alignement.
En effet, lorsque vous transmettez un char*
à std::ostream
, il affiche la chaîne de style C (c'est-à-dire: tableau de caractères, char*
) vers lequel il pointe.
Rappelez-vous que "hello"
est un char*
.
L'adresse de char est traitée comme une chaîne terminée par zéro et affiche le contenu de cette adresse, qui est probablement non définie, mais dans ce cas une chaîne vide. Si vous lancez les pointeurs sur void *
, vous obtiendrez les résultats souhaités.
La différence entre quelque chose 2 et 8 étant due à l'alignement et à la capacité du compilateur à décider lui-même où les variables sont déclarées dans la pile.
Pour le deuxième problème - le compilateur par défaut complétera les membres de la structure. Le pad par défaut correspond à sizeof(int)
, 4 octets (sur la plupart des architectures). C'est pourquoi une int
suivie d'une char
prendra 8 octets dans la structure, donc le membre string
est à l'offset 8.
Pour désactiver le remplissage, utilisez #pragma pack(x)
, où x est la taille du pad en octets.
Votre syntaxe devrait être
cout << (void*) &b
hrnt a raison sur la raison du blanc: &b
est de type char*
et est donc imprimé sous forme de chaîne jusqu'au premier octet nul. Vraisemblablement, b
est égal à 0. Si vous définissez b
sur, par exemple, 'A', vous devez alors vous attendre à ce que la sortie imprimée soit une chaîne commençant par 'A' et se poursuivant avec un déchet jusqu'au octet zéro suivant. Utilisez static_cast<void*>(&b)
pour l’imprimer sous forme d’adresse.
Pour votre deuxième question, &c - &i
est 8, car la taille d'un int est de 4, le caractère est de 1 et la chaîne commence à la limite de 8 octets suivante (vous êtes probablement sur un système 64 bits). Chaque type a un alignement particulier et C++ aligne les champs de la structure en fonction, en ajoutant le remplissage de manière appropriée. (La règle de base est qu'un champ primitif de taille N est aligné sur un multiple de N.) En particulier, vous pouvez ajouter 3 autres champs char
après b
sans affecter l'adresse &c
.