¿Por qué no se muestra la dirección de los datos de char?

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

El resultado es:

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

¿Por qué?

Otra cosa interesante: si int, char, string está en público, entonces la salida es

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

something_2 - something siempre es igual a 8. ¿Por qué? (no 9)

Cuando tomas la dirección de b, obtienes char * . operator<< interpreta eso como una cadena C, e intenta imprimir una secuencia de caracteres en lugar de su dirección.

try cout << "address of char :" << (void *) &b << endl en cout << "address of char :" << (void *) &b << endl lugar.

[EDITAR] Como lo comentó Tomek, un molde más apropiado para usar en este caso es static_cast , que es una alternativa más segura. Aquí hay una versión que lo usa en lugar del molde de estilo C:

 cout << "address of char :" << static_cast(&b) << endl; 

Hay 2 preguntas:

  • Por qué no imprime la dirección del char:

Al imprimir los punteros, se imprimirá la dirección para int* y la string* pero se imprimirá el contenido para char* ya que hay una sobrecarga especial en el operator<< . Si desea la dirección, utilice: static_cast(&c);

  • Por qué la diferencia de dirección entre el int y la string es 8

En su plataforma sizeof(int) es 4 y sizeof(char) es 1 por lo que debería preguntar por qué 8 no 5 . La razón es que la cadena está alineada en un límite de 4 bytes. Las máquinas trabajan con palabras en lugar de bytes, y funcionan más rápido si las palabras no se "dividen" unos pocos bytes aquí y unos pocos allí. Esto se llama alineamiento

Su sistema probablemente se alinee con los límites de 4 bytes. Si tuviera un sistema de 64 bits con enteros de 64 bits, la diferencia sería 16.

(Nota: el sistema de 64 bits generalmente se refiere al tamaño de un puntero, no a un int. Por lo tanto, un sistema de 64 bits con un int de 4 bytes aún tendría una diferencia de 8 como 4 + 1 = 5 pero redondea hasta 8 . Si sizeof (int) es 8, entonces 8 + 1 = 9 pero esto redondea hasta 16)

Cuando transmite la dirección de un char a un ostream, lo interpreta como la dirección del primer carácter de una cadena ASCIIZ “C-style” e intenta imprimir la cadena presunta. No tiene un terminador NUL, por lo que la salida seguirá tratando de leer desde la memoria hasta que encuentre uno o el sistema operativo lo apague por intentar leer desde una dirección no válida. Toda la basura que escanea se enviará a su salida.

Probablemente pueda hacer que muestre la dirección que desea al convertirla, como en (void*)&b .

Con respecto a las compensaciones en la estructura: observaste que la cuerda está colocada en offset 8. Esto es probablemente porque tienes enteros de 32 bits, luego un char de 8 bits, luego el comstackdor elige insertar otros 3 caracteres de 8 bits para que el el objeto de cadena se alineará en un límite de palabra de 32 bits. Muchas CPU / architectures de memoria necesitan punteros, ints, etc. para estar en límites de tamaño de palabra para realizar operaciones eficientes sobre ellas, y tendrían que hacer muchas más operaciones para leer y combinar múltiples valores de la memoria antes de poder usar los valores en una operación Dependiendo de su sistema, puede ser que cada objeto de clase necesite comenzar en un límite de palabra, o puede ser que std::string en particular comience con un tamaño_t, un puntero u otro tipo que requiera dicha alineación.

Porque cuando pasa un char* a std::ostream , imprimirá la cadena de estilo C (es decir: char array, char* ) a la que apunta.

Recuerde que "hello" es un char* .

La dirección de char se trata como una cadena terminada en nulo y muestra el contenido de esa dirección, que probablemente no está definida, pero en este caso es una cadena vacía. Si lanzas los punteros al void * , obtendrás los resultados que deseas.

La diferencia entre algo2 y algo que es 8 se debe a la alineación y capacidad del comstackdor para decidir por sí mismo en qué parte de la stack se declaran las variables.

Para el segundo problema, el comstackdor formará por defecto miembros de estructura de pad. El pad predeterminado es para el sizeof(int) , 4 bytes (en la mayoría de las architectures). Esta es la razón por la cual un int seguido de un char tomará 8 bytes en la estructura, por lo que el miembro de la string estará en offset 8.

Para deshabilitar el relleno, use #pragma pack(x) , donde x es el tamaño del panel en bytes.

Tu syntax debe ser

 cout << (void*) &b 

hrnt tiene razón sobre el motivo del espacio en blanco: &b tiene tipo char* , y así se imprime como una cadena hasta el primer byte cero. Presumiblemente, b es 0. Si configura b como, por ejemplo, ‘A’, entonces debe esperar que la impresión sea una cadena que comience por ‘A’ y continúe con la basura hasta el próximo byte cero. Utilice static_cast(&b) para imprimirlo como una dirección.

Para su segunda pregunta, &c - &i es 8, porque el tamaño de un int es 4, el char es 1 y la cadena comienza en el siguiente límite de 8 bytes (probablemente esté en un sistema de 64 bits). Cada tipo tiene una alineación particular, y C ++ alinea los campos en la estructura de acuerdo con ella, agregando relleno adecuadamente. (La regla de oro es que un campo primitivo de tamaño N está alineado con un múltiplo de N.) En particular, puede agregar 3 campos de caracteres más después de b sin afectar la dirección &c .