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 strcpyfunzione 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.