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í:
Cada uma das seguintes instruções se aplica, a menos que seja explicitamente declarado de outra forma nas descrições detalhadas a seguir: Se um argumento para uma função tiver um valor inválido ( como um valor fora do domínio da função ou um ponteiro fora do espaço de endereço do programa, ou um ponteiro nulo , [... outros exemplos ...] ) [...] o comportamento é indefinido. [... outras afirmações ...]
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:
A strcpy
função copia a string apontada por s2
(incluindo o caractere nulo de terminação) para a matriz apontada por s1
. Se a cópia ocorrer entre objetos que se sobrepõem, o comportamento é indefinido.
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:
[7.6.4.1 (fenv)] armazena o ambiente de ponto flutuante atual no objeto apontado porenvp
[7.12.6.4 (frexp)] armazenar o inteiro no objeto int apontado porexp
[7.19.5.1 (fclose)] o fluxo apontado porstream
Exemplo 2 - printf
[7.19.6.1] diz isso sobre %p
:
p
- O argumento deve ser um indicador para void
. O valor do ponteiro é convertido em uma seqüência de caracteres de impressão, de uma maneira definida pela implementação.
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.