Por que o endereço de dados char não é exibido?

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

A saída é:

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

Por quê?

Outra coisa interessante: se int, char, string está em público, então a saída é

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

something_2 - something é sempre igual a 8. Por quê? (não 9)

    Quando você está pegando o endereço de b, você obtém char * . operator< < interpreta isso como uma string C e tenta imprimir uma seqüência de caracteres em vez de seu endereço.

    tente cout < < "address of char :" << (void *) &b << endl vez disso.

    [EDIT] Como Tomek comentou, um casting mais apropriado para usar neste caso é o static_cast , que é uma alternativa mais segura. Aqui está uma versão que usa em vez do modelo de estilo C:

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

    Existem duas perguntas:

    • Por que não imprime o endereço do char:

    A impressão dos pointers imprimirá o endereço para o int* e a string* mas imprimirá o conteúdo para char* pois há uma sobrecarga especial no operator< < . Se você quiser o endereço, use: static_cast(&c);

    • Por que a diferença de endereço entre o int e a string é 8

    Na sua plataforma sizeof(int) é 4 e sizeof(char) é 1 então você deve perguntar por que 8 não 5 . A razão é que a cadeia está alinhada em um limite de 4 bytes. As máquinas trabalham com palavras em vez de bytes e trabalham mais rápido se as palavras não forem "divididas" por alguns bytes aqui e alguns bytes. Isso é chamado de alinhamento

    Seu sistema provavelmente se alinha aos limites de 4 bytes. Se você tivesse um sistema de 64 bits com inteiros de 64 bits, a diferença seria 16.

    (Nota: sistema de 64 bits geralmente se refere ao tamanho de um ponteiro, não a um int. Portanto, um sistema de 64 bits com um int de 4 bytes ainda teria uma diferença de 8 como 4 + 1 = 5, mas arredonda para 8 Se sizeof (int) é 8, então 8 + 1 = 9, mas isso arredonda para 16

    Quando você transmitir o endereço de um caractere para um ostream, ele interpretará esse como sendo o endereço do primeiro caractere de uma cadeia “C-style” em ASCIIZ e tentará imprimir a cadeia presumida. Você não tem um terminador NUL, portanto, a saída continuará tentando ler da memory até encontrar um ou o sistema operacional desligar para tentar ler de um endereço inválido. Todo o lixo que ele escaneia será enviado para a sua saída.

    Você provavelmente pode obtê-lo para exibir o endereço desejado, lançando-o, como em (void*)&b .

    Re os offsets na estrutura: você observou que a string é colocada no offset 8. Isto é provavelmente porque você tem ints de 32-bit, então um char de 8-bits, então o compilador escolhe para inserir mais 3 chars de 8 bits para que o object string será alinhado em um limite de palavra de 32 bits. Muitas CPUs / arquiteturas de memory precisam que pointers, ints etc. estejam em limites de tamanho de palavra para executar operações eficientes neles e, caso contrário, precisariam fazer muito mais operações para ler e combinar vários valores da memory antes de poder usar os valores em uma operação. Dependendo do seu sistema, pode ser que todo object de class precise iniciar em um limite de palavra, ou pode ser que std::string em particular inicie com um tamanho_t, um ponteiro ou outro tipo que exija tal alinhamento.

    Porque quando você passa um char* para std::ostream ele imprime a string C (isto é: char char, char* ) para a qual ele aponta.

    Lembre-se que "hello" é um char* .

    O endereço de char está sendo tratado como uma string terminada em nul e está exibindo o conteúdo desse endereço, que é provavelmente indefinido, mas, neste caso, uma string vazia. Se você converter os pointers para void * , você obterá os resultados desejados.

    A diferença entre algo2 e algo sendo 8 é devido ao alinhamento e capacidade do compilador decidir por si mesmo onde na pilha as variables ​​são declaradas.

    Para o segundo problema – o compilador por padrão irá preencher os membros da estrutura. O pad padrão é o sizeof(int) , 4 bytes (na maioria das arquiteturas). É por isso que um int seguido por um char terá 8 bytes na estrutura, portanto, o membro da string está no deslocamento 8.

    Para desabilitar o preenchimento, use #pragma pack(x) , onde x é o tamanho do bloco em bytes.

    Sua syntax deve ser

     cout < < (void*) &b 

    hrnt está certo sobre o motivo do espaço em branco: &b tem o tipo char* , e então é impresso como uma string até o primeiro byte zero. Presumivelmente b é 0. Se você definir b para, digamos, ‘A’, então você deve esperar que a impressão seja uma string começando com ‘A’ e continuando com lixo até o próximo byte zero. Use static_cast(&b) para imprimi-lo como um endereço.

    Para sua segunda pergunta, &c - &i é 8, porque o tamanho de um int é 4, o char é 1 e o string inicia no próximo limite de 8 bytes (você provavelmente está em um sistema de 64 bits). Cada tipo tem um alinhamento específico e C ++ alinha os campos na estrutura de acordo com ele, adicionando preenchimento de forma apropriada. (A regra geral é que um campo primitivo de tamanho N está alinhado a um múltiplo de N.) Em particular, você pode adicionar mais 3 campos de char após b sem afetar o endereço &c .