¿Es posible definir un parámetro de puntero ambiguo de signo para una función en C y / o C ++?

Por ejemplo, digamos que tengo una función que funciona tanto en tipos firmados como sin firmar de una variable de 8 bits y la función toma un puntero a la variable que se va a procesar / manipular.

Sé que puedo encasillar con (unsigned char *) o (firmado char *) pero estoy buscando algo más limpio.

unsigned char Var1;
signed char Var2;

void MyFunction(unsigned char* Var);

MyFunction(&Var2); // This creates an error

Dicho esto, me gusta mencionar la idea que tenía de que los lenguajes superiores al ensamblaje no deberían usar nombres como BYTE / WORD / DWORD o QWORD para definir una variable con un tipo de signo explícito. Digo esto porque estos son operadores de tamaño para ensamblar y en realidad no definen una señal. La asamblea de inicio de sesión se elige según la instrucción elegida. Sin embargo, veo que estos nombres se usan en todas partes en C / C ++ y se definen como sin marca, al menos en Windows. Esto me parece un conflicto de intereses ...

-6
AlwaysNub 17 oct. 2018 a las 00:25

2 respuestas

La mejor respuesta

Con C, tiene opciones limitadas. Puedes hacer el encasillado que no te guste cuando llames a la función:

void MyFunction(unsigned char* Var);

int main(void) {
    unsigned char Var1 = 5U;
    signed char Var2 = 5;

    MyFunction(&Var1);
    MyFunction((unsigned char *)&Var2);
}

Puede usar void * y encasillar en la función en sí y simplemente no pasarle el tipo incorrecto de puntero:

void MyFunction(void* Var);

int main(void) {
    unsigned char Var1 = 5U;
    signed char Var2 = 5;

    MyFunction(&Var1);
    MyFunction(&Var2);
}

O si realmente quiere algo más allá de eso, puede usar una macro _Generic para encasillarlo automágicamente. Puede que sea o no el "mejor" enfoque, pero creo que logrará su objetivo.

#define MY_FUNCTION_HELPER(X) MyFunction( _Generic((X), \
   char *: (unsigned char *)X, \
   signed char *: (unsigned char *)X, \
   unsigned char *: X \
   ) \
)

void MyFunction(unsigned char *Var);

int main(void) {
    unsigned char Var1 = 5U;
    signed char Var2 = 5;

    MY_FUNCTION_HELPER(&Var1);
    MY_FUNCTION_HELPER(&Var2);
}

El último funciona usando el _Generic introducido en C11 que permite que una forma de polimorfismo use diferentes expresiones basadas en el tipo de expresión de control. En este caso, si X es char * o signed char *, realizará un encasillado a unsigned char *. Si X ya es unsigned char *, permanecerá como tal. Si X es cualquier otra cosa, no se podrá compilar ya que no se tienen en cuenta otros tipos en la lista de asociaciones genéricas.

1
Christian Gibbons 16 oct. 2018 a las 22:26

Si la lógica para los dos tipos de objetos es la misma, su mejor opción es usar una plantilla de función.

template <typename T>
void MyFunction(T* Var);

Si desea restringir el uso de la función solo para tipos de 8 bits, puede usar un static_assert en la implementación.

template <typename T>
void MyFunction(T* Var)
{
   static_assert(sizeof(T) == 1, "Wrong type. Can only deal with 8-bit types.");
   ...
}
1
R Sahu 16 oct. 2018 a las 21:39