Byte ponteiro aritmética de precisão em C quando sizeof (char)! = 1
-
16-09-2019 - |
Pergunta
Como pode um portably executar a aritmética de ponteiros com precisão byte único?
Tenha em mente que:
-
char
não é 1 byte em todas as plataformas -
sizeof(void) == 1
só está disponível como uma extensão no GCC - Enquanto algumas plataformas podem ter ponteiro deref restrições de alinhamento ponteiro, aritmética pode ainda exigir uma granularidade mais fina do que o tamanho do menor tipo POD fundamentais
Solução
Seu pressuposto é falho -. sizeof(char)
é definido para ser 1 em todos os lugares
A partir da C99 padrão (TC3) , na seção 6.5.3.4 ( "O operador sizeof"):
(parágrafo 2)
O operador sizeof produz o tamanho (Em bytes) do seu operando, o qual pode ser uma expressão ou o nome entre parênteses de um tipo.
(parágrafo 3)
Quando aplicado a um operando que tem tipo char não assinado carvão animal, ou assinado char, (ou uma versão qualificada do mesmo) o resultado é 1.
Quando estes são tomados em conjunto, torna-se claro que em C, qualquer que seja o tamanho de um char é, que o tamanho é um "byte" (mesmo que seja mais de 8 bits, em alguma determinada plataforma).
A char
é, portanto, o menor tipo endereçável. Se você precisa resolver em unidades menores do que um char
, sua única opção é para ler um char
de cada vez e uso bit a bit operadores para mascarar as partes do char
que você deseja.
Outras dicas
De acordo com o char
padrão é o menor pedaço endereçável de dados. Você simplesmente não pode endereço com maior precisão -. Você precisa fazer as malas / descompactar manualmente
sizeof(char)
é garantido para ser 1
pelo padrão C. Mesmo se char
usa 9 bits ou mais.
Assim que você pode fazer:
type *pt;
unsigned char *pc = (unsigned char *)pt;
E o uso pc
para a aritmética. Atribuindo pc
para pt
utilizando o molde acima é comportamento indefinido pela norma C embora.
Se char
é mais do que 8-bits de largura, você não pode fazer byte de precisão aritmética de ponteiro no portátil (ANSI / ISO) C. Aqui, pela byte , quero dizer 8 bits. Isso ocorre porque o próprio tipo fundamental é maior do que 8 bits.
converter o ponteiro a um uintptr_t
. Este será um inteiro sem sinal que é do tamanho de um ponteiro. Agora faça a sua aritmética sobre ele, em seguida, lançar a volta resultado para um ponteiro do tipo que você deseja excluir a referência.
(Note que intptr_t
é assinado, o que geralmente não é o que você quer! É mais seguro ficar com uintptr_t
menos que você tenha uma boa razão para não!)
Eu não entendo o que você está tentando dizer com sizeof(void)
sendo 1 em GCC. Enquanto tipo char
pode teoricamente consistir em mais de 1 byte máquina subjacente, em linguagem C sizeof(char)
é 1 e sempre exatamente 1. Em outras palavras, do ponto de vista da linguagem C, char
é sempre 1 "byte" (C-byte, não byte máquina). Depois de entender isso, você também iria entender que sizeof(void)
sendo 1 em GCC não ajudá-lo de qualquer forma. Em GCC a aritmética de ponteiro em ponteiros void *
funciona exatamente da mesma forma que a aritmética de ponteiro em ponteiros char *
, o que significa que, se em algum char *
plataforma não funciona para você, então void *
não vai funcionar para você também.
Se em alguma plataforma objetos char
consistir em vários bytes da máquina, a única maneira de acessar unidades menores de memória do que um objeto char
completa seria a utilização de operações bit a bit para "extrair" e "modificar" as partes necessárias de um char
completa objeto. linguagem C não oferece nenhuma maneira de diretamente endereço de qualquer coisa menor que char
. Mais uma vez char
é sempre um C-byte.
O padrão C99 define o uint8_t que é um byte. Se o compilador não suporta este tipo, você poderia defini-lo usando um typedef. Claro que você precisa de uma definição diferente, dependendo da plataforma e / ou compilador. tudo o pacote em um arquivo de cabeçalho e usá-lo em todos os lugares.