Questo è uno di quegli strani casi d'angolo in cui siamo soggetti alle limitazioni della lingua inglese e alla struttura incoerente nello standard. Quindi, nella migliore delle ipotesi, posso fare una controargomentazione convincente, poiché è impossibile dimostrarlo :) 1
Il codice nella domanda mostra un comportamento ben definito.
Poiché [7.1.4] è la base della domanda, iniziamo da lì:
Ognuna delle seguenti affermazioni si applica a meno che non sia diversamente specificato nelle descrizioni dettagliate che seguono: Se un argomento di una funzione ha un valore non valido ( come un valore al di fuori del dominio della funzione, o un puntatore al di fuori dello spazio degli indirizzi del programma, o un puntatore nullo , [... altri esempi ...] ) [...] il comportamento è indefinito. [... altre dichiarazioni ...]
Questo è un linguaggio goffo. Un'interpretazione è che gli elementi nell'elenco sono UB per tutte le funzioni di libreria, a meno che non vengano sovrascritti dalle singole descrizioni. Ma l'elenco inizia con "come", a indicare che è illustrativo, non esaustivo. Ad esempio, non menziona la corretta terminazione nulla delle stringhe (fondamentale per il comportamento di eg strcpy
).
Quindi è chiaro che lo scopo / ambito di 7.1.4 è semplicemente che un "valore non valido" porta a UB ( se non diversamente specificato ). Dobbiamo guardare alla descrizione di ogni funzione per determinare cosa conta come un "valore non valido".
Esempio 1 - strcpy
[7.21.2.3] dice solo questo:
La strcpy
funzione copia la stringa a cui punta s2
(incluso il carattere null di terminazione) nell'array a cui punta s1
. Se la copia avviene tra oggetti che si sovrappongono, il comportamento è indefinito.
Non fa menzione esplicita di puntatori nulli, ma non fa nemmeno menzione di terminatori nulli. Invece, si deduce da "stringa puntata da s2
" che gli unici valori validi sono le stringhe (cioè i puntatori a matrici di caratteri con terminazione null).
In effetti, questo modello può essere visto in tutte le descrizioni individuali. Alcuni altri esempi:
[7.6.4.1 (fenv)] memorizza l'ambiente in virgola mobile corrente nell'oggetto puntato daenvp
[7.12.6.4 (frexp)] memorizza il numero intero nell'oggetto int puntato daexp
[7.19.5.1 (fclose)] lo stream puntato dastream
Esempio 2 - printf
[7.19.6.1] dice questo su %p
:
p
- L'argomento deve essere un puntatore a void
. Il valore del puntatore viene convertito in una sequenza di caratteri di stampa, in un modo definito dall'implementazione.
Null è un valore di puntatore valido e questa sezione non menziona esplicitamente che null è un caso speciale, né che il puntatore deve puntare a un oggetto. Quindi è definito comportamento.
1. A meno che non si faccia avanti un autore di standard, oa meno che non riusciamo a trovare qualcosa di simile a un documento razionale che chiarisca le cose.