¿Operador condicional con un valor constante (verdadero)?

2 minutos de lectura

avatar de usuario
jww

Estaba mirando algunas macros de preprocesador utilizadas en OpenSSL y me encontré con lo siguiente de crypto/stack/safestack.h:

#define CHECKED_STACK_OF(type, p) \
    ((_STACK*) (1 ? p : (STACK_OF(type)*)0))

#define CHECKED_SK_FREE_FUNC(type, p) \
    ((void (*)(void *)) ((1 ? p : (void (*)(type *))0)))

#define CHECKED_SK_FREE_FUNC2(type, p) \
    ((void (*)(void *)) ((1 ? p : (void (*)(type))0)))

Supongo que está escrito de esa manera para solucionar un error del compilador (probablemente algo antiguo que el proveedor no ha respaldado en más de una década).

¿Cuál es el propósito de usar el 1 arriba ya que siempre es verdad?

  • Verificando el tipo de pprobablemente: el segundo y tercer operandos del operador condicional deben poder convertirse al mismo tipo.

    – CT

    21 de diciembre de 2014 a las 2:59

avatar de usuario
2501

Es un código que verifica dos veces si se pasa el tipo correcto. El puntero p se pasa y junto con el tipo de ese puntero también se debe escribir manualmente en la macro.

La expresión ternaria siempre devolverá el segundo operando, pero tanto el segundo como el tercer operando se verificarán si su tipo coincide, y si no es así, debería obtener un error de compilación.

Un ejemplo sencillo:

int* p = NULL ;

1 ? p : ( float* )p ;    //error

1 ? p : ( int* )p ;      //ok

Es una afirmación estática sobre el tipo de función antes de la conversión, lo que proporciona una conversión segura de tipos.

De C11 (n1570) 6.5.15 (de la sección de restricciones)

operador condicional

(3) Uno de los siguientes se cumplirá para el segundo y tercer operandos:

  • [omitted non-pointer stuff]
  • ambos operandos son punteros a versiones calificadas o no calificadas de tipos compatibles;
  • un operando es un puntero y el otro es una constante de puntero nulo; o
  • un operando es un puntero a un tipo de objeto y el otro es un puntero a una versión calificada o no calificada de void.

El tercer operando es un puntero a una función (por lo que la última viñeta nunca se aplica), por lo que se compila (sin advertencia) solo si p es una constante de puntero nulo o de un tipo compatible con void (*)(type) para la última macro (después de la conversión a un puntero de función, si p es un designador de función).

¿Ha sido útil esta solución?