Quando um ponteiro para um tipo específico (por exemplo int
, char
, float
, ..) é incrementado, o seu valor é aumentado pelo tamanho de que tipo de dados. Se um void
ponteiro que aponta para dados de tamanho x
é incrementado, como ele aponta os x
bytes à frente? Como o compilador sabe agregar x
valor ao ponteiro?
c
pointers
void-pointers
pointer-arithmetic
Siva Sankaran
fonte
fonte
void
ponteiro que aponta para dados de tamanhox
é incrementado, como ele aponta osx
bytes à frente?" Não faz. Por que as pessoas que têm essas perguntas não podem testá-las antes de perguntar - você sabe, pelo menos ao mínimo, onde verificam se realmente compila, o que não acontece. -1, não posso acreditar que isso tenha +100 e -0.Respostas:
Conclusão final: aritmética em a
void*
é ilegal em C e C ++.O GCC permite isso como uma extensão, consulte Aritmética sobre
void
- e Ponteiros de função (observe que esta seção faz parte do capítulo "Extensões C" do manual)). Clang e ICC provavelmente permitemvoid*
aritmética para fins de compatibilidade com o GCC. Outros compiladores (como o MSVC) desabilitam a aritméticavoid*
e o GCC o desabilita se o-pedantic-errors
sinalizador for especificado ou se o-Werror-pointer-arith
sinalizador for especificado (esse sinalizador é útil se sua base de código também precisar compilar com o MSVC).O padrão C fala
As cotações são retiradas do rascunho n1256.
A descrição da norma da operação de adição indica:
Portanto, a questão aqui é se
void*
é um ponteiro para um "tipo de objeto" ou, equivalentemente, sevoid
é um "tipo de objeto". A definição para "tipo de objeto" é:E o padrão define
void
como:Como
void
é um tipo incompleto, não é um tipo de objeto. Portanto, não é um operando válido para uma operação de adição.Portanto, você não pode executar aritmética de ponteiro em um
void
ponteiro.Notas
Originalmente, pensava-se que a
void*
aritmética era permitida, devido a essas seções do padrão C:Contudo,
Portanto, isso significa que
printf("%s", x)
tem o mesmo significado, sejax
typechar*
ouvoid*
, mas não significa que você possa fazer aritmética em avoid*
.Nota do editor: Esta resposta foi editada para refletir a conclusão final.
fonte
void*
aritmética dos ponteiros não é permitida. O GCC tem uma extensão que permite fazer isso.void*
aritmética (pelo menos por padrão).Aritmética de ponteiro não é permitida em
void*
ponteiros.fonte
void
é um tipo incompleto que nunca pode ser concluído por definição.converta-o em um ponteiro de char e aumente seu ponteiro para a frente x bytes à frente.
fonte
char
, incrementarx
e depois reinterpretar o novo valor como algum outro tipo é um comportamento inútil e indefinido.man 3 qsort
deve ter ovoid qsort(void *base, size_t nmemb, size_t size, [snip])
, então você tem nenhuma maneira de saber o "tipo certo"O padrão C não permite aritmética de ponteiro nulo . No entanto, GNU C é permitido pelo considerando o tamanho do vazio é
1
.Norma C11 §6.2.5
Nº 19
O programa a seguir está funcionando bem no compilador GCC.
Outros compiladores podem gerar um erro.
fonte
Você não pode fazer aritmética de ponteiro nos
void *
tipos, exatamente por esse motivo!fonte
Você deve convertê-lo em outro tipo de ponteiro antes de fazer a aritmética do ponteiro.
fonte
Ponteiros nulos podem apontar para qualquer pedaço de memória. Portanto, o compilador não sabe quantos bytes aumentar / diminuir quando tentamos aritmética de ponteiro em um ponteiro nulo. Portanto, os ponteiros nulos devem primeiro ser convertidos para um tipo conhecido antes que possam ser envolvidos em qualquer aritmética de ponteiro.
fonte
O compilador sabe por tipo de conversão. Dado um
void *x
:x+1
adiciona um byte ax
, o ponteiro vai ao bytex+1
(int*)x+1
adicionasizeof(int)
bytes, o ponteiro vai para o bytex + sizeof(int)
(float*)x+1
sizeof(float)
bytes de endereço , etc.Embora o primeiro item não seja portátil e seja contra o Galateo do C / C ++, ele é correto na linguagem C, o que significa que ele será compilado com algo na maioria dos compiladores que talvez exijam uma sinalização apropriada (como -Wpointer-arith)
fonte
Althought the first item is not portable and is against the Galateo of C/C++
Verdade.it is nevertheless C-language-correct
Falso. Isso é duplo-pensamento! A aritmética do ponteirovoid *
é sintaticamente ilegal, não deve ser compilada e, se o fizer, produz um comportamento indefinido. Se um programador descuidado puder compilá-lo desativando algum aviso, isso não é desculpa.unsigned char*
por exemplo, adicionar umsizeof
valor a um ponteiro.