Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Yoel Alejandro en 27 Marzo 2014, 19:03 pm



Título: Promoción de los parámetros numéricos pasados a función ?
Publicado por: Yoel Alejandro en 27 Marzo 2014, 19:03 pm
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?


Título: Re: Promoción de los parámetros numéricos pasados a función ?
Publicado por: amchacon en 27 Marzo 2014, 22:21 pm
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
  1. #include <stdio.h>
  2.  
  3. void Printf(const char* texto,void* args[]);
  4.  
  5. int main()
  6. {
  7.    void* argumentos[3];
  8.    int a = 0;
  9.    float b = 3.2;
  10.    char c = 'e';
  11.  
  12.    argumentos[0] = &a;
  13.    argumentos[1] = &b;
  14.    argumentos[2] = &c;
  15.  
  16.    Printf("Texto: %d  %f  %c",argumentos);
  17.    return 0;
  18. }
  19.  
  20. void Printf(const char* texto,void* args[])
  21. {
  22.    int argumento = 0;
  23.    int i;
  24.    for (i = 0;texto[i];i++)
  25.    {
  26.        if (texto[i] != '%') putchar(texto[i]);
  27.        else
  28.        {
  29.            if (texto[i+1] == '\0'){putchar('%'); return;}
  30.  
  31.            switch (texto[i+1])
  32.            {
  33.            case 'd':
  34.                    {
  35.                        int aux = *((int*)args[argumento]);
  36.                        printf("%d",aux);
  37.                        argumento++;
  38.                        i++;
  39.                        break;
  40.                    }
  41.            case 'f':
  42.                    {
  43.                        float aux = *((float*)args[argumento]);
  44.                        printf("%f",aux);
  45.                        argumento++;
  46.                        i++;
  47.                        break;
  48.  
  49.                    }
  50.            case 'c':
  51.                    {
  52.                        char aux = *((char*)args[argumento]);
  53.                        printf("%c",aux);
  54.                        argumento++;
  55.                        i++;
  56.                        break;
  57.                    }
  58.            default:    putchar('%');
  59.            }
  60.        }
  61.    }
  62. }


Título: Re: Promoción de los parámetros numéricos pasados a función ?
Publicado por: rir3760 en 28 Marzo 2014, 03:35 am
(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:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int fn(int i, ...);
  5.  
  6. int main(void)
  7. {
  8.   int i = 1;
  9.   float x = 2.0F;
  10.   float y = 3.0F;
  11.  
  12.   printf("%d\n", fn(i, x, y));
  13.  
  14.   return EXIT_SUCCESS;
  15. }
Las "default argument promotions" se aplicaran a los argumentos "x" y "y".

có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.

(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


Título: Re: Promoción de los parámetros numéricos pasados a función ?
Publicado por: Yoel Alejandro en 28 Marzo 2014, 09:44 am
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?


Título: Re: Promoción de los parámetros numéricos pasados a función ?
Publicado por: rir3760 en 28 Marzo 2014, 16:03 pm
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


Título: Re: Promoción de los parámetros numéricos pasados a función ?
Publicado por: Yoel Alejandro en 30 Marzo 2014, 18:24 pm
Gracias, un saludo.