webentwicklung-frage-antwort-db.com.de

Warum wird die Adresse der Zeichendaten nicht angezeigt?

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

Die Ausgabe ist:

         address of int    :  something
         address of char   :     // nothing, blank area, that is nothing displayed
         address of string :  something 

Warum?

Eine andere interessante Sache: Wenn int, char, string in public ist, dann ist die Ausgabe

  ... int    :  something 
  ... char   :   
  ... string :  something_2

something_2 - something ist immer gleich 8. Warum? (nicht 9)

44
user478571

Wenn Sie die Adresse von b übernehmen, erhalten Sie char *. operator<< interpretiert das als C-String und versucht, anstelle der Adresse eine Zeichenfolge zu drucken.

versuchen Sie stattdessen cout << "address of char :" << (void *) &b << endl.

[EDIT] Wie Tomek kommentiert, ist static_cast eine geeignetere Methode, die verwendet werden kann. Dies ist eine sicherere Alternative. Hier ist eine Version, die es anstelle des C-Stils verwendet:

cout << "address of char   :" << static_cast<void *>(&b) << endl;
72
hrnt

Es gibt zwei Fragen:

  • Warum wird die Adresse des Zeichens nicht gedruckt:

Druckzeiger drucken die Adresse für den int*und den string*, aber den Inhalt für char* nicht, da in operator<< eine spezielle Überladung vorliegt. Wenn Sie die Adresse wünschen, verwenden Sie: static_cast<const void *>(&c);

  • Warum ist der Adressunterschied zwischen der int und der string8

Auf Ihrer Plattform ist sizeof(int)4 und sizeof(char) ist 1. Sie sollten sich also wirklich fragen, warum 8 nicht 5. Der Grund dafür ist, dass der String an einer 4-Byte-Grenze ausgerichtet ist. Maschinen arbeiten mit Wörtern statt mit Bytes und arbeiten schneller, wenn Wörter hier nicht einige Bytes und einige Bytes "aufgeteilt" werden. Dies wird alsAusrichtungbezeichnet.

Ihr System stimmt wahrscheinlich mit 4-Byte-Grenzen überein. Wenn Sie ein 64-Bit-System mit 64-Bit-Ganzzahlen hätten, wäre der Unterschied 16.

(Hinweis: 64-Bit-System bezieht sich im Allgemeinen auf die Größe eines Zeigers, nicht auf ein Int.) Ein 64-Bit-System mit einem 4-Byte-Int würde also immer noch eine Differenz von 8 als 4 + 1 = 5 aufweisen, aber auf 8 runden Wenn sizeof (int) 8 ist, dann ist 8 + 1 = 9, aber es wird auf 16 gerundet.

23
CashCow

Wenn Sie die Adresse eines Zeichens in einen Ostream streamen, interpretiert es diese als Adresse des ersten Zeichens einer ASCIIZ-Zeichenfolge "C-style" und versucht, die vermutete Zeichenfolge zu drucken. Sie haben kein NUL-Abschlusszeichen, so dass die Ausgabe so lange versucht, aus dem Speicher zu lesen, bis eine gefunden wird oder das Betriebssystem heruntergefahren wird, um zu versuchen, von einer ungültigen Adresse zu lesen. Der gesamte gescannte Müll wird an Ihre Ausgabe gesendet.

Sie können wahrscheinlich die gewünschte Adresse anzeigen lassen, indem Sie sie wie in (void*)&b umwandeln.

Betrachten Sie die Offsets in der Struktur: Sie haben beobachtet, dass der String an Offset 8 platziert ist. Dies liegt wahrscheinlich daran, dass Sie 32-Bit-Ints haben, dann ein 8-Bit-Zeichen, und der Compiler wählt dann 3 weitere 8-Bit-Zeichen aus String-Objekt wird an einer 32-Bit-Word-Grenze ausgerichtet. Viele CPUs/Speicherarchitekturen benötigen Zeiger, Ints usw., um sich an Grenzen der Word-Größe zu befinden, um effiziente Operationen an ihnen durchzuführen. Andernfalls müssten viele weitere Vorgänge ausgeführt werden, um mehrere Werte aus dem Speicher zu lesen und zu kombinieren, bevor die Werte verwendet werden können in einer Operation. Abhängig von Ihrem System kann es sein, dass jedes Klassenobjekt an einer Word-Grenze beginnen muss, oder es kann sein, dass std::string insbesondere mit einem size_t, einem Zeiger oder einem anderen Typ beginnt, der eine solche Ausrichtung erfordert.

13
Tony Delroy

Wenn Sie einen char* an std::ostream übergeben, wird die Zeichenfolge im C-Stil (dh Char Array, char*) gedruckt, auf die sie verweist.

Denken Sie daran, dass "hello" ein char* ist.

10
peoro

Die Adresse von char wird als nicht endende Zeichenfolge behandelt und zeigt den Inhalt dieser Adresse an, die wahrscheinlich undefiniert ist, in diesem Fall jedoch eine leere Zeichenfolge. Wenn Sie die Zeiger auf void * setzen, erhalten Sie die gewünschten Ergebnisse.

Der Unterschied zwischen etwas2 und etwas 8 ist auf die Ausrichtung und die Fähigkeit des Compilers zurückzuführen, selbst zu entscheiden, wo im Stack die Variablen deklariert werden.

4
trojanfoe

Für das zweite Problem - der Compiler füllt standardmäßig Strukturmitglieder auf. Das Standard-Pad enthält die sizeof(int), 4 Byte (bei den meisten Architekturen). Aus diesem Grund nimmt eine int, gefolgt von einer char, 8 Bytes in der Struktur ein, sodass das string-Member am Offset 8 ist.

Um das Auffüllen zu deaktivieren, verwenden Sie #pragma pack(x), wobei x die Pad-Größe in Byte ist.

2
Eli Iser

Deine Syntax sollte sein 

cout << (void*) &b
2
Taranfx

hrnt hat recht mit dem Grund für das Leerzeichen: &b hat den Typ char* und wird daher bis zum ersten Null-Byte als Zeichenfolge gedruckt. Vermutlich ist b 0. Wenn Sie b beispielsweise auf 'A' setzen, sollten Sie davon ausgehen, dass der Ausdruck eine Zeichenfolge ist, die mit 'A' beginnt und bis zum nächsten Null-Byte mit Müll fortgesetzt wird. Verwenden Sie static_cast<void*>(&b), um es als Adresse zu drucken.

Für Ihre zweite Frage ist &c - &i 8, da die Größe eines int 4 ist, das Zeichen 1 ist und die Zeichenfolge an der nächsten 8-Byte-Grenze beginnt (Sie befinden sich wahrscheinlich auf einem 64-Bit-System). Jeder Typ hat eine bestimmte Ausrichtung, und C++ richtet die Felder in der Struktur entsprechend aus, wobei die Auffüllung entsprechend hinzugefügt wird. (Die Faustregel besagt, dass ein primitives Feld der Größe N an einem Vielfachen von N ausgerichtet ist.) Insbesondere können Sie nach char drei weitere b-Felder hinzufügen, ohne die Adresse &c zu beeinflussen.

0
DS.