2011-01-12 11 views

Respuesta

4

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

+0

¿Hay alguna razón en particular para esta restricción? ¿Quizás algo relacionado con la implementación 'va_arg'? –

+1

@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). –

2

Esto parece ser una restricción glibc, el estándar C no tiene eso.

La idea detrás de esto es que los tipos de enteros que tienen los llamados "rango de conversión" más pequeño que int automáticamente se transfieren a signed o unsignedint. Una función va_arg encuentra entonces un argumento más amplio. La macro va_arg debe leer primero el argumento más amplio del tipo int, por ejemplo, y luego devolverlo al tipo original.

(mismo vale para float w.r.t a double.)

Para el programador conscientes que esto puede tener resultado sorprendente, por lo que están de acuerdo con la idea de que esto debe ser evitado. La descripción que está citando parece implicar que se impone no usar un tipo pequeño. Esto es falso y, como dije, no está alineado con el estándar. Por otro lado, si escribe código, ya que sugieren que nunca tendrá un problema de portabilidad porque es una restricción y no una extensión.

+2

Que yo sepa, Matthew tiene razón y usted está equivocado; esta restricción * es * en C99 al menos. Si lo piensas, sería muy, muy difícil, no juraría que es imposible, pero el estándar C en general ha evitado poner requisitos meramente difíciles en las implementaciones, para hacer una implementación "tradicional" de 'va_arg' (uno que no se expande a un compilador intrínseco) sin esta restricción, dado que la promoción del argumento ocurre en la persona que llama. – zwol

+0

@Zack: digamos que la redacción es al menos ambigua, el alcance del "como promovido ..." no está claro. Pero no estoy de acuerdo con usted en que permitir tipos limitados supone * mucho * carga para la implementación. Simplemente tendrían que verificar los tipos angostos, leer un argumento del tipo promocionado (una implementación tiene que saber cómo encontrar ese tipo, de todos modos) y devolver el valor al tipo angosto. –

+2

Eso sería algo fácil de hacer * desde un compilador intrínseco *. La implementación tradicional de 'va_arg' no tiene acceso a tales comodidades; hace todo con expresiones de lenguaje central (técnicamente indefinidas). Como C no incluye ninguna forma de metaprogramación de tipos, no creo que pueda "encontrar un argumento del tipo promocionado y volver al tipo angosto" utilizando solo expresiones del lenguaje central. – zwol