Promoción de los parámetros numéricos pasados a función ?

Iniciado por Yoel Alejandro, 27 Marzo 2014, 19:03 PM

0 Miembros y 2 Visitantes están viendo este tema.

Yoel Alejandro

Leyendo en internet encontré la cita:

Citar
Cuidado con los tipos. Tengan en cuenta que por defecto C hace promoción de los parámetros pasados, así, si pasan un float, este será promovido a double y la sentencia va_arg(pa,float) será incorrecta. Lo mismo con shorts, etc. Normalmente el compilador nos avisará de esto.

El tema se refiere a funciones con número variable argumentos, donde lógicamente debemos avisar a la macro va_arg sobre el tipo esperado del siguiente argumento de la función. La verdad nunca antes había leído de ésto, pero según entiendo de la cita si se pasa un float a la función, de alguna manera promueve el argumento a double, i.e., reserva en la pila de argumentos, en el lugar asignado para el mismo, el espacio que ocupa un double en lugar del espacio que ocupa un float. En este caso desreferenciar el argumento (usando va_arg) como float dará un error, como es de suponer.

Tengo dos inquietudes: (1) ¿Cuándo ocurren dichas "promociones", y cómo podemos hacer entonces para trabajar de manera segura?

(2) Se me ocurre que una forma de controlar dichas promociones es hacer cast explícito de los argumentos pasados, ejemplo: f( (float) x, (float) y ), así invocará la función reservando en la pila de argumentos el espacio justo para argumentos de tipo float. ¿Es correcto?
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

amchacon

El tema de los argumentos infinitos es un poco polémico. Si te da igual el método empleado puedes usar un array de punteros void*, aquí un ejemplo de uso en una implementación de printf:

Código (cpp) [Seleccionar]
#include <stdio.h>

void Printf(const char* texto,void* args[]);

int main()
{
    void* argumentos[3];
    int a = 0;
    float b = 3.2;
    char c = 'e';

    argumentos[0] = &a;
    argumentos[1] = &b;
    argumentos[2] = &c;

    Printf("Texto: %d  %f  %c",argumentos);
    return 0;
}

void Printf(const char* texto,void* args[])
{
    int argumento = 0;
    int i;
    for (i = 0;texto[i];i++)
    {
        if (texto[i] != '%') putchar(texto[i]);
        else
        {
            if (texto[i+1] == '\0'){putchar('%'); return;}

            switch (texto[i+1])
            {
            case 'd':
                    {
                        int aux = *((int*)args[argumento]);
                        printf("%d",aux);
                        argumento++;
                        i++;
                        break;
                    }
            case 'f':
                    {
                        float aux = *((float*)args[argumento]);
                        printf("%f",aux);
                        argumento++;
                        i++;
                        break;

                    }
            case 'c':
                    {
                        char aux = *((char*)args[argumento]);
                        printf("%c",aux);
                        argumento++;
                        i++;
                        break;
                    }
            default:    putchar('%');
            }
        }
    }
}
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

rir3760

Cita de: yoel_alejandro en 27 Marzo 2014, 19:03 PM(1) ¿Cuándo ocurren dichas "promociones"
Ocurren en dos escenarios. Cuando:
A) No hay prototipo previo a la llamada a función se aplican a todos los argumentos.
B) Se llama a una función con un numero variable de argumentos se aplican a los argumentos correspondientes a los parámetros sin nombre. Para explicarlo mejor en este ejemplo:
#include <stdio.h>
#include <stdlib.h>

int fn(int i, ...);

int main(void)
{
   int i = 1;
   float x = 2.0F;
   float y = 3.0F;
   
   printf("%d\n", fn(i, x, y));
   
   return EXIT_SUCCESS;
}

Las "default argument promotions" se aplicaran a los argumentos "x" y "y".

Cita de: yoel_alejandro en 27 Marzo 2014, 19:03 PMcómo podemos hacer entonces para trabajar de manera segura?
Ya lo estas haciendo. El mejor ejemplo es printf y familia, con ellas cualquier valor de tipo char, short y float que pases se convertirá en int y double. No hay problema.

Cita de: yoel_alejandro en 27 Marzo 2014, 19:03 PM(2) Se me ocurre que una forma de controlar dichas promociones es hacer cast explícito de los argumentos pasados, ejemplo: f( (float) x, (float) y ), así invocará la función reservando en la pila de argumentos el espacio justo para argumentos de tipo float. ¿Es correcto?
No. Ello porque primero se evalúan los argumentos de la función y solo entonces se promocionan. Siguiendo tu ejemplo primero se evalúa la expresión  "(float) x" resultando en (por supuesto) el valor de la variable "x" convertido al tipo float, a continuación se aplican las promociones convirtiendo ese valor al tipo double.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Yoel Alejandro

Las promociones, en caso de funciones con número variable de argumentos, serían entonces:

* char, unsigned char, short, unsigned short, pasan a int
* float pasa a double

¿sólo esas?
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

rir3760

Casi (es un poco mas complicado).

Las "default argument promotions" son:
1) "Integral promotions".
2) Tipo float se convierte a double.

Las "Integral promotions" son:
1) signed char y signed short pasan a signed int.
2) unsigned char y unsigned short pasan a signed int si este puede almacenar todos los valores de los dos primeros tipos, en caso contrario se convierten a unsigned int.

El tipo "char" es equivalente a signed char o unsigned char (depende de la implementación).

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Yoel Alejandro

Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)