Aquí está el C99 standard; Los tipos de "autopromoción" son aquellos que se promocionan a sí mismos cuando se aplican las promociones de argumento predeterminado (§6.5.2.2 párrafo 6, que hace referencia a las promociones enteras descritas en §6.3.1.1).
Mi lectura de la definición va_arg
(§7.15.1.1) es que esta limitación es implícita en el estándar. La parte pertinente se encuentra en el párrafo 2:
[...] o si tipo no es compatible con el tipo del siguiente argumento real (como se promueve de acuerdo a las promociones de argumentos por defecto) [... ]
que es bastante claro el tipo del siguiente argumento real que está siendo promovido, pero como no lee decir nada sobre el tipo está promoviendo. (Creo que la cláusula "(como promovido ...)" es solo un recordatorio de que las promociones predeterminadas de argumento se realizan en los argumentos finales cuando se llama a una función varargs.)
Este elemento en la lista de comportamiento indefinido en § J.2 apoya esta lectura:
- la macro va_arg
se invoca cuando no hay ningún argumento próxima real, o con un tipo especificado que no es compatible con el tipo promovido de lo actual argumento siguiente, con cierta excepciones (7.15.1.1).
(aunque sí, lo sé, el Anexo J es "informativo" en lugar de "normativo" ...).
En cuyo caso: va_arg(ap, float)
(por ejemplo) no puede ser válido - tipo en ese caso es float
, pero el tipo promovido del siguiente argumento real no puede ser posiblemente float
(un argumento float
sería promovido a double
).
¿Hay alguna razón en particular para esta restricción? ¿Quizás algo relacionado con la implementación 'va_arg'? –
@crypto: sospecho que Zack tiene razón (ver su respuesta a Jens); no hay una manera obvia de encontrar la promoción de argumento predeterminada de un tipo dado sin la ayuda especial del compilador, por lo que esto permite una implementación de 'va_arg (ap, type)' que funciona sin dicha ayuda. (por ejemplo, mantenga un puntero de bytes en el argumento actual en la pila en 'ap'; luego' va_arg' podría ser una macro horrible que se mueva al siguiente argumento fundiéndolo en 'type *', incrementando el puntero 'type *', y volviendo a un puntero de bytes). –