Qual é a diferença entre um ponteiro apontando para o local 0x0 e um ponteiro definido como NULL?

12

Um ponteiro apontando para 0x0000 é o mesmo que um ponteiro definido como NULL? Se o valor NULL for definido no idioma C, para que local ele traduz fisicamente? É o mesmo que 0x0000. Onde posso encontrar mais detalhes sobre esses conceitos?

Arpith
fonte
1
Isso já foi solicitado no Stack Overflow - stackoverflow.com/questions/1296843/… . Eu acho que é limítrofe para nós, mas estou disposto a dar o benefício da dúvida no momento.
ChrisF

Respostas:

12

Um ponto que a maioria das respostas aqui não aborda, pelo menos não explicitamente, é que um ponteiro nulo é um valor que existe durante a execução, e uma constante de ponteiro nulo é uma construção sintática que existe no código-fonte C.

Uma constante de ponteiro nulo , como a resposta de Karlson afirma corretamente, é uma expressão constante inteira com o valor 0 (um exemplo simples 0é o mais comum) ou uma expressão convertida em void*(como (void*)0).

NULLé uma macro, definida em <stddef.h>vários cabeçalhos padrão, que se expande para uma constante de ponteiro nulo definida pela implementação . A expansão geralmente é um 0ou outro ((void*)0)(os parênteses externos são necessários para satisfazer outras regras de idioma).

Portanto, um literal 0, quando usado em um contexto que requer uma expressão do tipo ponteiro, sempre avalia como um null pointervalor de ponteiro exclusivo que não aponta para nenhum objeto. Isso não implica nada na representação de um ponteiro nulo . Ponteiros nulos são comumente representados como todos os bits zero, mas podem ser representados como qualquer coisa. Mas mesmo que um ponteiro nulo é representado como 0xDEADBEEF, 0ou (void*)0ainda é uma constante ponteiro nulo .

Esta resposta à pergunta sobre stackoverflow cobre isso muito bem.

Isso implica, entre outras coisas, que memset()ou calloc(), que pode definir uma região da memória para todos os bits-zero, não definirá necessariamente nenhum ponteiro nessa região como ponteiro nulo. É provável que o façam na maioria das implementações, mas a linguagem não garante isso.

Não sei por que essa pergunta não é considerada uma duplicata desta , nem como é atual aqui.

Keith Thompson
fonte
1
Um dos meus pontos de vista com o design e a evolução de C é que o dígito zero continuou a ser usado como uma representação não obsoleta de um ponteiro nulo. Nos primeiros dias da linguagem (por exemplo, antes do advento de coisas como protótipos de funções), ponteiros e números inteiros eram suficientemente intercambiáveis ​​que o uso de "0" para um ponteiro nulo era simples e "funcionaria". Uma vez que se tornou necessário distinguir entre a quantidade inteira zero e um ponteiro nulo, no entanto, a representação "0" deveria ter sido preterida em favor de uma palavra-chave ou sequência do operador.
Supercat 13/07/12
Isso significa que o ponteiro NULL pode realmente apontar para algum local quando é atribuído a NULL, dependendo da plataforma? A constante de ponteiro nulo talvez seja uma construção sintática, mas o que exatamente acontece quando o código é executado? Vamos supor que essa construção sintática tenha sido compilada na plataforma GNU / Linux. Qual é o valor do ponteiro quando atribuímos NULL a ele? Como esse endereço difere de qualquer outro endereço?
Arpith
1
@Arpith: atribuir NULL, ou qualquer constante de ponteiro nulo , a um objeto ponteiro define o valor desse objeto para um ponteiro nulo . No nível da máquina, pode muito bem apontar para algum pedaço de memória válido. A desreferencia de um ponteiro nulo tem um comportamento indefinido; acessar um pedaço de memória no endereço 0x0000000é um comportamento válido, como é literalmente qualquer outra coisa. Esse endereço difere de qualquer outro endereço por (a) comparar igual a NULLe (b) comparar desigual com qualquer ponteiro para um objeto C. Um ponteiro nulo é um valor arbitrário de ponteiro usado para indicar que não aponta para nada.
9308 Keith Thompson
1
No nível da máquina, pode apontar para algum pedaço de memória válido, mas na maioria dos ambientes C apontará para memória inválida, para que qualquer tentativa de usar o ponteiro resulte em uma interceptação / falha / exceção de hardware. Geralmente, é apenas nas plataformas de hardware mais simples - aquelas sem suporte para gerenciamento de memória - onde um ponteiro NULL aponta para um local de memória válido.
Solomon Slow
7

Toda plataforma disponível é livre para definir NULL como quiser.

De acordo com o Padrão C, se você atribuir zero a um ponteiro, ele será convertido em um valor NULL (para essa plataforma). No entanto, se você pegar um ponteiro NULL e convertê-lo em int, não há garantias de que você obterá zero em todas as plataformas existentes. O fato, porém, é que, na maioria das plataformas, será zero.

Informações sobre esse material podem ser encontradas em The C Language Specification . Uma fonte cuja confiabilidade não posso garantir é a seguinte: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

Mike Nakis
fonte
2
Se eles optarem por se afastar do padrão, terão liberdade para redefinir NULL pointer constant. Até onde eu sei, não existem compiladores que façam isso.
197 Karl Karlson
Existe algum compilador por aí que não implemente NULL como 0? E NULL é garantido para avaliar como falso?
ugoren
NULL é garantido para avaliar como falso pelo padrão. Não sei se existe algum compilador (plataforma, na verdade) que não implemente NULL como 0, e duvido seriamente, mas o padrão não o proíbe, então quem sabe.
perfil completo de Mike Nakis
Há confusão entre a representação da "constante constante do ponteiro nulo" abstrata (como mencionado na especificação) na memória, que pode ser a vontade do criador da plataforma, e a definição de NULLmacro, que deve ser expandida para 0C ++ e C 0ou (void *)0porque essa é a verdadeira "constante de ponteiro nulo".
precisa saber é o seguinte
Embora NULL possa, em teoria, ser definido como qualquer coisa, existe, no entanto, uma garantia pelo padrão de que uma constante int com o valor 0 tipificado para um ponteiro resultará em um ponteiro nulo (ISO 9899: 1999 6.3.2.3/3). A macro NULL do stddef.h deve ser um ponteiro nulo (7.17 / 3); portanto, seria muito oneroso para o compilador não implementar NULL como 0 ou (vazio *) 0.
1

É definido na linguagem C porque não há um endereço de máquina invariável ao qual ele se iguala. Se isso acontecesse, não precisaríamos de uma abstração! Embora na maioria das plataformas, o NULL possa eventualmente ser implementado como 0 de um tipo ou de outro, é simplesmente errado supor que isso seja universalmente verdade, se você se importa com a portabilidade.

Kilian Foth
fonte
Isso é o que os padrões são para open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Karlson
0

De acordo com a seção do documento padrão C6.3.2.3 :

Uma expressão constante inteira com o valor 0, ou uma expressão convertida para digitar void *, é chamada de constante de ponteiro nulo.55) Se uma constante de ponteiro nulo é convertida em um tipo de ponteiro, o ponteiro resultante, chamado de ponteiro nulo, é garantido para comparar desigual a um ponteiro para qualquer objeto ou função.

Até agora, eu não vi um compilador que se separou disso.

Karlson
fonte
@ PéterTörök Você está certo, é um erro de digitação. :)
Karlson
1
Sim, mas observe que ele não diz nada sobre o ponteiro realmente ter valor numérico igual a 0. Pode não, embora na maioria das plataformas o faça.
Jan Hudec