É um comportamento indefinido imprimir ponteiros nulos com o %p
especificador de conversão?
#include <stdio.h>
int main(void) {
void *p = NULL;
printf("%p", p);
return 0;
}
A questão se aplica ao padrão C, e não às implementações C.
c
language-lawyer
c99
undefined-behavior
c11
Dror K.
fonte
fonte
Respostas:
Este é um daqueles casos estranhos em que estamos sujeitos às limitações do idioma inglês e à estrutura inconsistente do padrão. Portanto, na melhor das hipóteses, posso apresentar um contra-argumento convincente, pois é impossível prová- lo :) 1
O código em questão exibe um comportamento bem definido.
Como [7.1.4] é a base da pergunta, vamos começar por aí:
Esta é uma linguagem desajeitada. Uma interpretação é que os itens na lista são UB para todas as funções da biblioteca, a menos que sejam substituídos pelas descrições individuais. Mas a lista começa com "como", indicando que é ilustrativa, não exaustiva. Por exemplo, não menciona a terminação nula correta de strings (crítica para o comportamento de eg
strcpy
).Portanto, está claro que a intenção / escopo de 7.1.4 é simplesmente que um "valor inválido" leva ao UB (a menos que indicado de outra forma ). Temos que olhar para a descrição de cada função para determinar o que conta como um "valor inválido".
Exemplo 1 -
strcpy
[7.21.2.3] diz apenas o seguinte:
Ele não faz nenhuma menção explícita de ponteiros nulos, mas também não faz menção de terminadores nulos. Em vez disso, infere-se de "string apontado por
s2
" que os únicos valores válidos são strings (ou seja, ponteiros para matrizes de caracteres terminados em nulo).Na verdade, esse padrão pode ser visto em todas as descrições individuais. Alguns outros exemplos:
Exemplo 2 -
printf
[7.19.6.1] diz isso sobre
%p
:Nulo é um valor de ponteiro válido e esta seção não faz menção explícita de que nulo é um caso especial, nem que o ponteiro deve apontar para um objeto. Assim, é um comportamento definido.
1. A menos que um autor de padrões apareça, ou a menos que possamos encontrar algo semelhante a um documento lógico que esclareça as coisas.
fonte
A resposta curta
Sim . A impressão de ponteiros nulos com o
%p
especificador de conversão tem comportamento indefinido. Dito isso, não tenho conhecimento de qualquer implementação em conformidade existente que se comportaria mal.A resposta se aplica a qualquer um dos padrões C (C89 / C99 / C11).
A resposta longa
O
%p
especificador de conversão espera um argumento do tipo ponteiro para void, a conversão do ponteiro em caracteres imprimíveis é definida pela implementação. Ele não afirma que um ponteiro nulo é esperado.A introdução às funções de biblioteca padrão afirma que ponteiros nulos como argumentos para funções (biblioteca padrão) são considerados valores inválidos, a menos que seja explicitamente declarado de outra forma.
C99
/C11
§7.1.4 p1
Exemplos de funções (biblioteca padrão) que esperam ponteiros nulos como argumentos válidos:
fflush()
usa um ponteiro nulo para liberar "todos os fluxos" (que se aplicam).freopen()
usa um ponteiro nulo para indicar o arquivo "atualmente associado" ao fluxo.snprintf()
permite passar um ponteiro nulo quando 'n' é zero.realloc()
usa um ponteiro nulo para alocar um novo objeto.free()
permite passar um ponteiro nulo.strtok()
usa um ponteiro nulo para chamadas subsequentes.Se considerarmos o caso
snprintf()
, faz sentido permitir a passagem de um ponteiro nulo quando 'n' é zero, mas este não é o caso para outras funções (biblioteca padrão) que permitem um zero 'n' semelhante. Por exemplo:memcpy()
,memmove()
,strncpy()
,memset()
,memcmp()
.Não é especificado apenas na introdução à biblioteca padrão, mas também mais uma vez na introdução a estas funções:
C99 §7.21.1 p2
/C11 §7.24.1 p2
É intencional?
Eu não sei se o UB de
%p
com um ponteiro nulo é de fato intencional, mas como o padrão afirma explicitamente que os ponteiros nulos são considerados valores inválidos como argumentos para funções de biblioteca padrão, ele vai e especifica explicitamente os casos em que um nulo ponteiro é um argumento válido (snprintf, livre, etc), e então ele vai e mais uma vez repete a exigência para os argumentos para ser válido, mesmo em casos de zeros 'n' (memcpy
,memmove
,memset
), então eu acho que é razoável supor que o O comitê de padrões C não está muito preocupado em ter essas coisas indefinidas.fonte
%p
não deveria ser um comportamento indefinidoOs autores do Padrão C não fizeram nenhum esforço para listar exaustivamente todos os requisitos comportamentais que uma implementação deve atender para ser adequada a qualquer propósito específico. Em vez disso, eles esperavam que as pessoas que escreviam compiladores exercessem uma certa dose de bom senso, quer o padrão exigisse ou não.
A questão de saber se algo invoca UB raramente é útil por si só. As verdadeiras questões importantes são:
Alguém que está tentando escrever um compilador de qualidade deve fazer com que ele se comporte de maneira previsível? Para o cenário descrito, a resposta é claramente sim.
Os programadores devem ter o direito de esperar que compiladores de qualidade para qualquer coisa semelhante a plataformas normais se comportem de maneira previsível? No cenário descrito, eu diria que a resposta é sim.
Poderiam alguns escritores de compiladores obtusos esticar a interpretação do Padrão de modo a justificar fazer algo estranho? Eu esperava que não, mas não descartaria.
A higienização de compiladores deve reclamar do comportamento? Isso dependeria do nível de paranóia de seus usuários; um compilador de limpeza provavelmente não deveria reclamar por padrão sobre tal comportamento, mas talvez forneça uma opção de configuração para fazer no caso de programas serem portados para compiladores "inteligentes" / burros que se comportam de maneira estranha.
Se uma interpretação razoável do Padrão implicaria que um comportamento é definido, mas alguns redatores do compilador ampliam a interpretação para justificar o contrário, realmente importa o que o Padrão diz?
fonte
printf("%p", (void*) 0)
comportamento indefinido ou não, de acordo com o padrão? Chamadas de função profundamente aninhadas são tão relevantes quanto o preço do chá na China. E sim, UB é muito comum em programas do mundo real - e daí?%p
para cada possível significado da pergunta.