Uma implementação C em conformidade #define NULL como algo maluco

Estou perguntando por causa da discussão que foi provocada emesta discussão.

Tentar ter uma discussão séria e indireta usando comentários nas respostas de outras pessoas não é fácil nem divertido. Então, eu gostaria de ouvir o que nossos especialistas em C pensam sem se restringir a 500 caracteres por vez.

O padrão C tem poucas palavras preciosas a dizer sobreNULL constantes de ponteiro nulo. Há apenas duas seções relevantes que posso encontrar. Primeiro:

3.2.2.3 Ponteiros

Uma expressão constante integral com o valor 0, ou uma expressão convertida para digitar void *, é chamada constante de ponteiro nulo. Se uma constante de ponteiro nulo é atribuída ou comparada para igualdade a um ponteiro, a constante é convertida em um ponteiro desse tipo. Esse ponteiro, chamado ponteiro nulo, tem garantia de comparação desigual com um ponteiro com qualquer objeto ou função.

e em segundo lugar:

4.1.5 Definições comuns

As macros são

NULL

que se expande para uma constante de ponteiro nulo definida pela implementação;

A questão é, podeNULL expandir para uma constante de ponteiro nulo definida pela implementação que é diferente daquela enumerada no 3.2.2.3?

Em particular, poderia ser definido como:

#define NULL __builtin_magic_null_pointer

Ou até:

#define NULL ((void*)-1)

Minha leitura de 3.2.2.3 é que especifica que uma expressão constante integral de 0 e uma expressão constante integral de 0 convertida para digitar void * devem estar entre as formas de constante de ponteiro nulo que a implementação reconhece, mas que não é destinado a ser uma lista exaustiva. Eu acredito que a implementação é livre para reconhecer outras construções de origem como constantes de ponteiro nulo, desde que nenhuma outra regra seja quebrada.

Por exemplo, é provável que

#define NULL (-1)

não é uma definição legal, porque em

if (NULL) 
   do_stuff(); 

do_stuff() não deve ser chamado, enquanto que com

if (-1)
   do_stuff();

do_stuff() deve ser chamado; como são equivalentes, essa não pode ser uma definição legal deNULL.

Mas o padrão diz que as conversões de número inteiro para ponteiro (e vice-versa) são definidas pela implementação, portanto, pode definir a conversão de -1 em um ponteiro como uma conversão que produz um ponteiro nulo. Nesse caso

if ((void*)-1) 

avaliaria como falso, e tudo ficaria bem.

Então, o que as outras pessoas pensam?

Peço a todos que tenham especialmente em mente a regra "como se" descrita em2.1.2.3 Program execution. É enorme e um tanto indireto, então não vou colá-lo aqui, mas basicamente diz que uma implementação apenas produz os mesmos efeitos colaterais observáveis que são exigidos pela máquina abstrata descrita pelo padrão. Ele diz que quaisquer otimizações, transformações ou qualquer outra coisa que o compilador queira fazer no seu programa é perfeitamente legal, desde que os efeitos colaterais observáveis do programa não sejam alterados por eles.

Portanto, se você deseja provar que uma definição específica deNULL não puder ser legal, você precisará criar um programa que possa provar isso. Qualquer um como o meu que flagrantemente quebra outras cláusulas do padrão, ou um que pode detectar legalmente qualquer mágica que o compilador tenha que fazer para fazer a definição nula estranha funcionar.

Steve Jessop encontrou um exemplo de caminho para um programa detectar issoNULL não está definido para ser uma das duas formas de constantes de ponteiro nulo no 3.2.2.3, que consiste em restringir a constante:

#define stringize_helper(x) #x
#define stringize(x) stringize_helper(x) 

Usando essa macro, pode-se

puts(stringize(NULL));

e "detecta" que o NULL não se expande para um dos formulários no 3.2.2.3. Isso é suficiente para tornar outras definições ilegais? Eu simplesmente não sei.

Obrigado!

questionAnswers(6)

yourAnswerToTheQuestion