2011-01-12 15 views

risposta

4

Ecco lo C99 standard; I tipi "auto-promuoventi" sono quelli che si promuovono quando vengono applicate le promozioni di argomento predefinito (paragrafo 6.5.2.2, paragrafo 6, che fa riferimento alle promozioni intere descritte in §6.3.1.1).

La mia lettura della definizione va_arg (§7.15.1.1) è che questa limitazione è implicita dallo standard. La parte rilevante è nel paragrafo 2:

[...] o se tipo non è compatibile con il tipo di argomento attuale successiva (come promosso secondo le promozioni di argomento di default) [... ]

che è abbastanza chiara sul tipo di argomento attuale successiva di essere promosso, ma ho letto da non dire nulla su tipo promosso. (Penso che la clausola "(come promosso ...)" sia solo un promemoria che le promozioni degli argomenti predefiniti vengono eseguite sugli argomenti finali quando viene chiamata una funzione varargs.)

Questo elemento nell'elenco di comportamento non definito in § J.2 supporta questa lettura:

- la va_arg macro viene invocato quando non v'è alcun argomento reale prossimo, o con un tipo specificato che non è compatibile con il tipo promosso del reale argomento successivo, con una certa eccezioni (7.15.1.1).

(anche se sì, lo so, l'allegato J è "informativo" piuttosto che "normativo" ...).

In questo caso: va_arg(ap, float) (per esempio) non può essere valido - tipo in questo caso è float, ma il tipo promosso dell'argomento effettiva successivo potrà eventualmente essere float (un argomento float sarebbe promosso double).

+0

C'è qualche motivo particolare per questa restrizione? Forse qualcosa a che fare con l'implementazione? Va_arg'? –

+1

@crypto: Sospetto che Zack abbia ragione (vedere la sua risposta a Jens); non c'è un modo ovvio per trovare la promozione di argomento predefinita di un dato tipo senza l'aiuto speciale del compilatore, quindi questo consente un'implementazione di va_arg (ap, type) 'che funziona senza tale aiuto. (ad esempio, mantieni un puntatore di byte all'argomento corrente sullo stack in "ap", quindi "va_arg" potrebbe essere una qualche orribile macro che passa all'argomento successivo eseguendo il cast di "type *", incrementando il puntatore "type *", e ritorno a un puntatore di byte.) –

2

Questa sembra essere una limitazione glibc, lo standard C non ha questo.

L'idea alla base di questo è che i tipi interi che sono i cosiddetti "conversione rango" inferiore rispetto int sono promossi automaticamente signed o unsignedint. Una funzione va_arg trova quindi un argomento più ampio. La macro va_arg deve quindi prima leggere l'argomento più ampio di tipo int, ad esempio, quindi ricondurlo al tipo originale.

(stesso vale per float w.r.t a double.)

Per il programmatore ignaro questo può avere sorprendente risultato, quindi sono d'accordo con l'idea che questo dovrebbe essere evitato. La descrizione che stai citando sembra implicare che si imponga di non usare un tipo piccolo. Questo è falso e come ho detto non in linea con lo standard. D'altra parte se si scrive codice come suggeriscono non si avrà mai un problema di portabilità con quello perché questa è una restrizione e non un'estensione.

+2

Per quanto ne so, Matteo ha ragione e si sbaglia; questa restrizione * è * almeno in C99. Se ci pensate, sarebbe molto, molto difficile - non giurerò su _impossible_, ma lo standard C ha generalmente evitato di imporre requisiti _difficult_ sulle implementazioni - per fare un'implementazione "tradizionale" di va_arg' (uno che non si espande in un compilatore intrinseco) senza questa restrizione, dato che la promozione degli argomenti avviene nel chiamante. – zwol

+0

@Zack: diciamo che la formulazione è quantomeno ambigua, l'ambito del "come promosso ..." non è chiaro. Ma non sono d'accordo con te sul fatto che il permettere tipi stretti imponga * molto * onere sull'implementazione. Dovrebbero solo verificare i tipi ristretti, leggere un argomento del tipo promosso (un'implementazione deve sapere come trovare quel tipo, comunque) e restituire il valore al tipo ristretto. –

+2

Sarebbe una cosa facile da fare * da un compilatore intrinseco *. L'implementazione tradizionale di 'va_arg' non ha accesso a tali comodità; fa tutto con espressioni linguistiche core (tecnicamente indefinite). Dato che C non include alcun modo di eseguire metaprogrammazione sui tipi, non credo che si possa "trovare un argomento del tipo promosso e ricondurre al tipo ristretto" usando solo espressioni linguistiche di base. – zwol