Pergunta

Eu gostaria de saber arquiteturas que violam as suposições Eu listei abaixo.Além disso, gostaria de saber se alguma das suposições é falsa para todas as arquiteturas (ou seja, se alguma delas está completamente errada).

  1. sizeof(int *) == sizeof(char *) == sizeof(void *) == sizeof(func_ptr *)

  2. A representação na memória de todos os ponteiros para uma determinada arquitetura é a mesma, independentemente do tipo de dados apontado.

  3. A representação na memória de um ponteiro é igual a um número inteiro com o mesmo comprimento de bits da arquitetura.

  4. Multiplicação e divisão de tipos de dados de ponteiro são proibidas apenas pelo compilador.OBSERVAÇÃO:Sim, eu sei que isso é absurdo.O que quero dizer é: existe suporte de hardware para proibir esse uso incorreto?

  5. Todos os valores de ponteiro podem ser convertidos em um único número inteiro.Em outras palavras, quais arquiteturas ainda utilizam segmentos e deslocamentos?

  6. Incrementar um ponteiro é equivalente a adicionar sizeof(the pointed data type) para o endereço de memória armazenado pelo ponteiro.Se p é um int32* então p+1 é igual ao endereço de memória 4 bytes depois p.

Estou mais acostumado com ponteiros usados ​​em um espaço de memória virtual contíguo.Para esse uso, geralmente consigo pensar neles como endereços em uma reta numérica.Consulte a pergunta Stack Overflow Comparação de ponteiro.

Foi útil?

Solução

Não posso dar exemplos concretos de tudo isso, mas farei o meu melhor.

sizeof(int *) == sizeof(char *) == sizeof(void *) == sizeof(func_ptr *)

Não conheço nenhum sistema onde eu saber isso é falso, mas considere:

Os dispositivos móveis geralmente têm uma certa quantidade de memória somente leitura na qual o código do programa e outros itens são armazenados.Valores somente leitura (variáveis ​​const) podem ser armazenados em memória somente leitura.E como o espaço de endereço da ROM pode ser menor que o espaço de endereço da RAM normal, o tamanho do ponteiro também pode ser diferente.Da mesma forma, os ponteiros para funções podem ter um tamanho diferente, pois podem apontar para esta memória somente leitura na qual o programa é carregado e que de outra forma não pode ser modificada (portanto, seus dados não podem ser armazenados nela).

Portanto, não conheço nenhuma plataforma em que tenha observado que o acima exposto não se aplica, mas posso imaginar sistemas onde possa ser o caso.

A representação na memória de todos os ponteiros para uma determinada arquitetura é a mesma, independentemente do tipo de dados apontado.

Pense em ponteiros de membros versus ponteiros regulares.Eles não têm a mesma representação (ou tamanho).Um ponteiro de membro consiste em um this ponteiro e um deslocamento.

E como acima, é concebível que algumas CPUs carreguem dados constantes em uma área separada da memória, que usa um formato de ponteiro separado.

A representação na memória de um ponteiro é igual a um número inteiro com o mesmo comprimento de bits da arquitetura.

Depende de como esse comprimento de bit é definido.:) Um int em muitas plataformas de 64 bits ainda é de 32 bits.Mas um ponteiro tem 64 bits.Como já dito, CPUs com modelo de memória segmentada terão ponteiros compostos por um par de números.Da mesma forma, os ponteiros membros consistem em um par de números.

Multiplicação e divisão de tipos de dados de ponteiro são proibidas apenas pelo compilador.

Em última análise, apenas tipos de dados de ponteiros existir no compilador.A CPU não trabalha com ponteiros, mas com números inteiros e endereços de memória.Portanto, não há nenhum outro lugar onde essas operações em tipos de ponteiro poderia ser proibido.Você também pode solicitar que a CPU proíba a concatenação de objetos de string C++.Isso não pode ser feito porque o tipo de string C++ existe apenas na linguagem C++, não no código de máquina gerado.

No entanto, para responder ao que você significar, procure as CPUs Motorola 68000.Acredito que eles tenham registros separados para números inteiros e endereços de memória.O que significa que eles podem facilmente proibir tais operações absurdas.

Todos os valores de ponteiro podem ser convertidos em um único número inteiro.

Você está seguro lá.Os padrões C e C++ garantem que isso sempre será possível, independentemente do layout do espaço de memória, da arquitetura da CPU e de qualquer outra coisa.Especificamente, eles garantem um mapeamento definido pela implementação.Em outras palavras, você sempre pode converter um ponteiro em um número inteiro e depois converter esse número inteiro novamente para obter o ponteiro original.Mas as linguagens C/C++ não dizem nada sobre qual deveria ser o valor inteiro intermediário.Isso depende do compilador individual e do hardware a que ele se destina.

Incrementar um ponteiro é equivalente a adicionar sizeof (o tipo de dados apontado) ao endereço de memória armazenado pelo ponteiro.

Novamente, isso é garantido.Se você considerar que conceitualmente, um ponteiro não aponta para um endereço, ele aponta para um objeto, então isso faz todo o sentido.Adicionar um ao ponteiro obviamente fará com que ele aponte para o próximo objeto.Se um objeto tiver 20 bytes de comprimento, incrementar o ponteiro o moverá 20 bytes, de modo que ele se mova para o próximo objeto.

Se um ponteiro fosse meramente um endereço de memória em um espaço de endereçamento linear, se fosse basicamente um número inteiro, então incrementá-lo adicionaria 1 ao endereço - isto é, ele passaria para o próximo byte.

Por fim, como mencionei em um comentário à sua pergunta, lembre-se de que C++ é apenas uma linguagem.Não importa para qual arquitetura ele é compilado.Muitas dessas limitações podem parecer obscuras nas CPUs modernas.Mas e se você estiver visando as CPUs do passado?E se você estiver visando as CPUs da próxima década?Você nem sabe como eles funcionarão, então não pode presumir muito sobre eles.E se você estiver almejando uma máquina virtual?Já existem compiladores que geram bytecode para Flash, pronto para rodar a partir de um site.E se você quiser compilar seu código-fonte C++ para Python?

Ficar dentro das regras especificadas no padrão garante que seu código funcionará em todos estes casos.

Outras dicas

Não tenho em mente exemplos específicos do mundo real, mas a "autoridade" é o padrão C.Se algo não for exigido pelo padrão, você poderá construir uma implementação em conformidade que intencionalmente não cumpra quaisquer outras suposições.Algumas dessas suposições são verdadeiras na maioria das vezes apenas porque é conveniente implementar um ponteiro como um número inteiro representando um endereço de memória que pode ser buscado diretamente pelo processador, mas isso é apenas uma consequência da "conveniência" e não pode ser mantido como uma verdade universal.

  1. Não exigido pela norma (veja esta pergunta).Por exemplo, sizeof(int*) pode ser desigual size(double*). void* é garantido que será capaz de armazenar qualquer valor de ponteiro.
  2. Não exigido pela norma.Por definição, o tamanho faz parte da representação.Se o tamanho puder ser diferente, a representação também poderá ser diferente.
  3. Não necessariamente.Na verdade, "o comprimento em bits de uma arquitetura" é uma afirmação vaga.O que é realmente um processador de 64 bits?É o barramento de endereços?Tamanho dos registros?Barramento de dados?O que?
  4. Não faz sentido “multiplicar” ou “dividir” um ponteiro.É proibido pelo compilador, mas é claro que você pode multiplicar ou dividir a representação subjacente (o que realmente não faz sentido para mim) e isso resulta em um comportamento indefinido.
  5. Talvez eu não entenda seu ponto, mas tudo em um computador digital é apenas algum tipo de número binário.
  6. Sim;tipo de.É garantido que aponta para um local que é um sizeof(pointer_type) mais.Não é necessariamente equivalente à adição aritmética de um número (ou seja, mais é um conceito lógico aqui.A representação real é específica da arquitetura)

Para 6.:um ponteiro não é necessariamente um endereço de memória.Veja por exemplo "A Grande Conspiração do Ponteiro"por usuário do Stack Overflow jalf:

Sim, usei a palavra “endereço” no comentário acima.É importante perceber o que quero dizer com isso.Não quero dizer “o endereço de memória no qual os dados são armazenados fisicamente”, mas simplesmente um resumo “tudo o que precisamos para localizar o valor.O endereço de i pode ser qualquer coisa, mas assim que o tivermos, sempre poderemos encontrar e modificar i."

E:

Um ponteiro não é um endereço de memória!Mencionei isso acima, mas vamos repetir.Os ponteiros são normalmente implementados pelo compilador simplesmente como endereços de memória, sim, mas não precisam ser."

Algumas informações adicionais sobre ponteiros do padrão C99:

  • 6.2.5 §27 garante que void* e char* têm representações idênticas, ou seja, podem ser usados ​​de forma intercambiável sem conversão, ou seja, o mesmo endereço é denotado pelo mesmo padrão de bits (o que não precisa ser verdadeiro para outros tipos de ponteiros)
  • 6.3.2.3 §1 afirma que qualquer ponteiro para um tipo de objeto ou incompleto pode ser convertido para (e de) void* e vice-versa e ainda será válido;isso não inclui ponteiros de função!
  • 6.3.2.3 §6 afirma que void* pode ser convertido para (e de) números inteiros e 7.18.1.4 §1 fornece tipos apropriados intptr_t e uintptr_t;o problema:esses tipos são opcionais - o padrão menciona explicitamente que não precisa haver um tipo inteiro grande o suficiente para realmente conter o valor do ponteiro!

sizeof(char*) != sizeof(void(*)(void) ?- Não funciona em x86 no modo de endereçamento de 36 bits (suportado em praticamente todas as CPUs Intel desde Pentium 1)

"A representação na memória de um ponteiro é igual a um número inteiro com o mesmo comprimento de bits" - não há representação na memória em nenhuma arquitetura moderna;a memória marcada nunca pegou e já estava obsoleta antes de C ser padronizado.Na verdade, a memória nem contém números inteiros, apenas bits e possivelmente palavras (não bytes;a maior parte da memória física não permite a leitura de apenas 8 bits.)

“Multiplicação de ponteiros é impossível” - família 68.000;registradores de endereços (aqueles que contêm ponteiros) não suportavam esse IIRC.

"Todos os ponteiros podem ser convertidos em números inteiros" - Não em PICs.

"Incrementar um T* é equivalente a adicionar sizeof(T) ao endereço de memória" - verdadeiro por definição.Também equivalente a &pointer[1].

Não sei sobre os outros, mas para o DOS, a suposição do item 3 não é verdadeira.O DOS é de 16 bits e usa vários truques para mapear muito mais que 16 bits de memória.

A representação na memória de um ponteiro é igual a um número inteiro com o mesmo comprimento de bits da arquitetura.

Acho que essa suposição é falsa porque no 80186, por exemplo, um ponteiro de 32 bits é mantido em dois registradores (um registrador de deslocamento e um registrador de segmento), e qual meia palavra foi inserida em qual registro é importante durante o acesso.

Multiplicação e divisão de tipos de dados de ponteiro são proibidas apenas pelo compilador.

Você não pode multiplicar ou dividir tipos.;P

Não sei por que você deseja multiplicar ou dividir um ponteiro.

Todos os valores de ponteiro podem ser convertidos em um único número inteiro.Em outras palavras, quais arquiteturas ainda utilizam segmentos e deslocamentos?

O padrão C99 permite que ponteiros sejam armazenados em intptr_t, que é um tipo inteiro.Então sim.

Incrementar um ponteiro é equivalente a adicionar sizeof (o tipo de dados apontado) ao endereço de memória armazenado pelo ponteiro.Se p for um int32* então p+1 é igual ao endereço de memória 4 bytes depois de p.

x + y onde x é um T * e y é um número inteiro equivalente a (T *)((intptr_t)x + y * sizeof(T)) até onde sei.O alinhamento pode ser um problema, mas o preenchimento pode ser fornecido no sizeof.Eu não tenho certeza.

Em geral, a resposta para todas as perguntas é "sim", e é porque apenas as máquinas que implementam linguagens populares diretamente viram a luz do dia e persistiram até o século atual.Embora os padrões linguísticos se reservem o direito de variar estes "invariantes", ou afirmações, isso nunca aconteceu em produtos reais, com a possível exceção dos itens 3 e 4 que requerem alguma reformulação para serem universalmente verdadeiros.

Certamente é possível construir projetos de MMU segmentados, que correspondem aproximadamente às arquiteturas baseadas em capacidade que eram populares academicamente nos últimos anos, mas nenhum sistema desse tipo normalmente tem uso comum com esses recursos habilitados.Tal sistema poderia ter entrado em conflito com as afirmações, pois provavelmente teria grandes indicadores.

Além dos MMUs segmentados/de capacidade, que geralmente possuem ponteiros grandes, projetos mais extremos tentaram codificar tipos de dados em ponteiros.Poucos deles foram construídos.(Esta questão traz à tona todas as alternativas para as arquiteturas básicas orientadas por palavras, um ponteiro-é-uma-palavra.)

Especificamente:

  1. A representação na memória de todos os ponteiros para uma determinada arquitetura é a mesma, independentemente do tipo de dados apontado. Verdade, exceto por designs anteriores extremamente malucos que tentavam implementar proteção não em linguagens fortemente tipadas, mas em hardware.
  2. A representação na memória de um ponteiro é igual a um número inteiro com o mesmo comprimento de bits da arquitetura. Talvez, certamente algum tipo de integral seja o mesmo, veja LP64 versus LLP64.
  3. Multiplicação e divisão de tipos de dados de ponteiro são proibidas apenas pelo compilador. Certo.
  4. Todos os valores de ponteiro podem ser convertidos em um único número inteiro.Em outras palavras, quais arquiteturas ainda utilizam segmentos e deslocamentos? Nada usa segmentos e deslocamentos hoje, mas um C int muitas vezes não é grande o suficiente, você pode precisar de um long ou long long para segurar um ponteiro.
  5. Incrementar um ponteiro é equivalente a adicionar sizeof (o tipo de dados apontado) ao endereço de memória armazenado pelo ponteiro.Se p for um int32* então p+1 é igual ao endereço de memória 4 bytes depois de p. Sim.

É interessante notar que cada CPU da arquitetura Intel, ou seja, cada PeeCee, contém uma elaborada unidade de segmentação de complexidade épica e lendária.No entanto, está efetivamente desativado.Sempre que um sistema operacional de PC é inicializado, ele define as bases dos segmentos como 0 e os comprimentos dos segmentos como ~0, anulando os segmentos e fornecendo um modelo de memória simples.

Houve muitas arquiteturas "endereçadas por palavras" nas décadas de 1950, 1960 e 1970.Mas não consigo me lembrar de nenhum exemplo convencional que tivesse um compilador C.Eu me lembro do Máquinas ICL / Three Rivers PERQ na década de 1980, era endereçado por palavra e tinha um armazenamento de controle gravável (microcódigo).Uma de suas instanciações tinha um compilador C e uma versão do Unix chamada PNX, mas o compilador C exigia um microcódigo especial.

O problema básico é que os tipos char* em máquinas com endereçamento de palavras são estranhos, independentemente de como você os implementa.Você costuma fazer sizeof(int *) != sizeof(char *) ...

Curiosamente, antes de C existia uma linguagem chamada BCPL em que o tipo básico de ponteiro era um endereço de palavra;isto é, incrementar um ponteiro fornece o endereço da próxima palavra e ptr!1 te dei a palavra em ptr + 1.Havia um operador diferente para endereçar um byte: ptr%42 se bem me lembro.

EDITAR:Não responda a perguntas quando o açúcar no sangue estiver baixo.Seu cérebro (certamente o meu) não funciona como você espera.:-(

Pequenos detalhes:

p é um int32* então p+1

está errado, ele precisa ser int32 não assinado, caso contrário, será agrupado em 2 GB.

Uma estranheza interessante - recebi isso do autor do compilador C para o chip Transputer - ele me disse que para esse compilador, NULL foi definido como -2GB.Por que?Porque o Transputer tinha um intervalo de endereços assinado:-2GB a +2GB.Você pode acreditar nisso?Incrível, não é?

Desde então, conheci várias pessoas que me disseram que definir NULL assim está quebrado.Eu concordo, mas se você não fizer isso, os ponteiros NULL estarão no meio do seu intervalo de endereços.

Acho que a maioria de nós pode estar feliz por não estarmos trabalhando no Transputers!

Gostaria de saber arquiteturas que violam as suposições que listei abaixo.

Vejo que Stephen C mencionou máquinas PERQ e MSalters mencionou 68000s e PICs.

Estou desapontado porque ninguém mais respondeu à pergunta nomeando qualquer uma das arquiteturas estranhas e maravilhosas que possuem compiladores C compatíveis com os padrões que não se enquadram em certas suposições injustificadas.

sizeof (int *) == sizeof (char *) == sizeof (void *) == sizeof (func_ptr *)?

Não necessariamente.Alguns exemplos:

A maioria dos compiladores para os processadores de 8 bits de Harvard-Architecture-PIC e 8051 e M8C-faz sizeof (int *) == sizeof (char *), mas diferente do sizeof (func_ptr *).

Alguns dos chips muito pequenos dessas famílias têm 256 bytes de RAM (ou menos), mas vários kilobytes de PROGMEM (Flash ou ROM), então os compiladores geralmente fazem sizeof(int *) == sizeof(char *) igual a 1 (um único byte de 8 bits), mas sizeof(func_ptr *) igual a 2 (dois bytes de 8 bits).

Compiladores para muitos dos chips maiores nessas famílias com alguns kilobytes de RAM e 128 ou mais kilobytes de PROGMEM tornam sizeof(int *) == sizeof(char *) igual a 2 (dois bytes de 8 bits), mas sizeof( func_ptr *) igual a 3 (três bytes de 8 bits).

Alguns chips da arquitetura Harvard podem armazenar exatamente 2 ^ 16 ("64 KByte") de PROGMEM (Flash ou ROM) e outros 2 ^ 16 ("64 KByte") de RAM + E/S mapeada em memória.Os compiladores para tal chip fazem com que sizeof(func_ptr *) seja sempre 2 (dois bytes);mas geralmente há uma maneira de transformar os outros tipos de ponteiros sizeof(int *) == sizeof(char *) == sizeof(void *) em um "long ptr" Ponteiro genérico de 3 bytes que possui o bit mágico extra que indica se o ponteiro aponta para RAM ou PROGMEM.(Esse é o tipo de ponteiro que você precisa passar para uma função "print_text_to_the_LCD()" quando você chama essa função de muitas sub-rotinas diferentes, às vezes com o endereço de uma string variável no buffer que pode estar em qualquer lugar na RAM, e outras vezes com um de muitas strings constantes que podem estar em qualquer lugar do PROGMEM).Esses compiladores geralmente têm palavras-chave especiais ("curto" ou "próximo", "longo" ou "longe") para permitir que os programadores indiquem especificamente três tipos diferentes de ponteiros char no mesmo programa - strings constantes que precisam apenas de 2 bytes para indicar onde no PROGMEM eles estão localizados, strings não constantes que precisam apenas de 2 bytes para indicar onde estão localizados na RAM e o tipo de ponteiros de 3 bytes que "print_text_to_the_LCD()" aceita.

A maioria dos computadores construídos nas décadas de 1950 e 1960 usa um Comprimento de palavra de 36 bits ou um Comprimento de palavra de 18 bits, com um barramento de endereço de 18 bits (ou menos).Ouvi dizer que os compiladores C para esses computadores costumam usar bytes de 9 bits, com sizeof (int *) == sizeof (func_ptr *) = 2 que fornece 18 bits, pois todos os números inteiros e funções precisam ser alinhados a palavras;mas sizeof(char *) == sizeof(void *) == 4 para aproveitar instruções especiais PDP-10 que armazenam esses ponteiros em uma palavra completa de 36 bits.Essa palavra completa de 36 bits inclui um endereço de palavra de 18 bits e mais alguns bits nos outros 18 bits que (entre outras coisas) indicam a posição do bit do caractere apontado dentro dessa palavra.

A representação na memória de todos os ponteiros para uma determinada arquitetura é a mesma, independentemente do tipo de dados apontado?

Não necessariamente.Alguns exemplos:

Em qualquer uma das arquiteturas mencionadas acima, os ponteiros vêm em tamanhos diferentes.Então, como eles poderiam ter “a mesma” representação?

Alguns compiladores em alguns sistemas usam "descritores" para implementar ponteiros de caracteres e outros tipos de ponteiros.Tal descritor é diferente para um ponteiro apontando para o primeiro "char" em um "char big_array[4000]" do que para um ponteiro apontando para o primeiro "caractere" em um "char small_array[10]", que são, sem dúvida, tipos de dados diferentes, mesmo quando o array pequeno começa exatamente no mesmo local na memória anteriormente ocupada pelo array grande.Os descritores permitem que essas máquinas capturem e capturem os buffer overflows que causam tais problemas em outras máquinas.

O "Indicadores com baixo teor de gordura" usados ​​​​no SAFElite e em "processadores suaves" semelhantes possuem "informações extras" análogas sobre o tamanho do buffer para o qual o ponteiro aponta.Ponteiros com baixo teor de gordura têm a mesma vantagem de capturar e capturar buffer overflows.

A representação na memória de um ponteiro é a mesma que um número inteiro do mesmo comprimento que a arquitetura?

Não necessariamente.Alguns exemplos:

Em "arquitetura marcada" máquinas, cada palavra de memória possui alguns bits que indicam se aquela palavra é um número inteiro, ou um ponteiro, ou qualquer outra coisa.Com essas máquinas, olhar para os bits da tag diria se a palavra era um número inteiro ou um ponteiro.

Ouvi dizer que os minicomputadores Nova têm um "bit de indireção" em cada palavra que inspirou "código encadeado indireto".Parece que armazenar um número inteiro limpa esse bit, enquanto armazenar um ponteiro define esse bit.

A multiplicação e a divisão dos tipos de dados do ponteiro são proibidos apenas pelo compilador.OBSERVAÇÃO:Sim, eu sei que isso é absurdo.O que quero dizer é - existe suporte de hardware para proibir esse uso incorreto?

Sim, alguns hardwares não suportam diretamente tais operações.

Como outros já mencionaram, a instrução "multiplicar" no 68000 e no 6809 funciona apenas com (alguns) "registros de dados";eles não podem ser aplicados diretamente a valores em "registros de endereços".(Seria muito fácil para um compilador contornar tais restrições - MOV esses valores de um registrador de endereço para o registrador de dados apropriado e então usar MUL).

Todos os valores de ponteiro podem ser convertidos em um único tipo de dados?

Sim.

Para que memcpy() para funcionar direito, o padrão C exige que todo valor de ponteiro de qualquer tipo possa ser convertido em um ponteiro nulo ("void *").

O compilador é necessário para fazer isso funcionar, mesmo para arquiteturas que ainda usam segmentos e deslocamentos.

Todos os valores de ponteiro podem ser convertidos em um único número inteiro?Em outras palavras, quais arquiteturas ainda usam segmentos e compensações?

Eu não tenho certeza.

Suspeito que todos os valores de ponteiro possam ser convertidos para os tipos de dados integrais "size_t" e "ptrdiff_t" definidos em "<stddef.h>".

Incrementar um ponteiro é equivalente a adicionar tamanho de (o tipo de dados pontiagudo) ao endereço de memória armazenado pelo ponteiro.Se p for um int32*, então P+1 é igual ao endereço de memória 4 bytes após p.

Não está claro o que você está perguntando aqui.

P:Se eu tiver uma matriz de algum tipo de estrutura ou tipo de dados primitivo (por exemplo, um "#include <stdint.h> ... int32_t example_array[1000]; ...") e incremento um ponteiro que aponta para esse array (por exemplo, "int32_t p = &example_array[99];...p++;..."), o ponteiro agora aponta para o próximo membro consecutivo dessa matriz, que é sizeof(o tipo de dados apontado) bytes mais adiante na memória?

A:Sim, o compilador deve fazer com que o ponteiro, após incrementá-lo uma vez, aponte para o próximo int32_t consecutivo independente na matriz, sizeof (o tipo de dados apontado) bytes mais adiante na memória, para ser compatível com os padrões.

P:Então, se p é um int32* , então p+1 é igual ao endereço de memória 4 bytes depois de p?

A:Quando sizeof( int32_t ) é realmente igual a 4, sim.Caso contrário, como para certas máquinas endereçáveis ​​por palavra, incluindo alguns DSPs modernos onde sizeof( int32_t ) pode ser igual a 2 ou mesmo 1, então p+1 é igual ao endereço de memória 2 ou mesmo 1 "bytes C" após p.

P:Então, se eu pegar o ponteiro e transformá-lo em um "int" ...

A:Um tipo de “Todo o mundo é uma heresia VAX”.

P:...e depois converta esse "int" em um ponteiro ...

A:Outro tipo de “Todo o mundo é uma heresia VAX”.

P:Então, se eu pegar o ponteiro p, que é um ponteiro para um int32_t, e convertê-lo em algum tipo integral que seja grande o suficiente para conter o ponteiro, e então adicionar sizeof( int32_t ) para esse tipo integral e, posteriormente, converter esse tipo integral de volta em um ponteiro - quando faço tudo isso, o ponteiro resultante é igual a p+1?

Não necessariamente.

Muitos DSPs e alguns outros chips modernos possuem endereçamento orientado a palavras, em vez do processamento orientado a bytes usado pelos chips de 8 bits.

Alguns dos compiladores C para esses chips colocam 2 caracteres em cada palavra, mas são necessárias 2 dessas palavras para conter um int32_t - então eles relatam que sizeof( int32_t ) é 4.(Ouvi rumores de que existe um compilador C para o 24 bits Motorola 56000 que faz isso).

O compilador é necessário para organizar as coisas de forma que fazer "p++" com um ponteiro para um int32_t incremente o ponteiro para o próximo valor int32_t.Existem várias maneiras de o compilador fazer isso.

Uma maneira compatível com os padrões é armazenar cada ponteiro para um int32_t como um "endereço de palavra nativo".Como são necessárias 2 palavras para conter um único valor int32_t, o compilador C compila "int32_t * p; ... p++" em alguma linguagem assembly que incremente o valor do ponteiro em 2.Por outro lado, se isso acontecer "int32_t * p; ... int x = (int)p; x += sizeof( int32_t ); p = (int32_t *)x;", esse compilador C para o 56000 provavelmente o compilará em linguagem assembly que incrementa o valor do ponteiro em 4.

Estou mais acostumado a ponteiros sendo usados ​​em um espaço de memória virtual contíguo.

Vários PIC e 8086 e outros sistemas têm RAM não contígua-alguns blocos de RAM em endereços que "tornaram o hardware mais simples".Com E/S mapeada em memória ou nada anexado às lacunas no espaço de endereço entre esses blocos.

É ainda mais estranho do que parece.

Em alguns casos - como no caso do hardware de banda de bits usado para evitar problemas causados ​​por ler-modificar-escrever - exatamente o mesmo bit na RAM pode ser lido ou escrito usando 2 ou mais endereços diferentes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top