2014-12-21 1 views
28

stavo guardando alcune macro di preprocessore utilizzati in OpenSSL, e mi sono imbattuto nel seguente da crypto/stack/safestack.h:Operatore condizionale con un valore costante (vero)?

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

Sto indovinando il suo scritto in quel modo per aggirare un bug del compilatore (probabilmente qualcosa di antico che hasn 'è stato supportato in oltre un decennio dal venditore).

Qual è lo scopo di utilizzare lo 1 in quanto è sempre vero?

+3

Verificare il tipo di 'p', probabilmente - il secondo e il terzo operando dell'operatore condizionale devono essere convertibili nello stesso tipo. –

risposta

25

È il codice che controlla se viene passato il tipo corretto. Il puntatore p viene passato e anche il tipo di tale puntatore deve essere digitato manualmente nella macro.

L'espressione ternaria restituirà sempre il secondo operando, ma il secondo e il terzo operando verranno controllati se il loro tipo corrisponde, e se non lo fanno si dovrebbe ottenere un errore del compilatore.

Un semplice esempio:

int* p = NULL ; 

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

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

Grazie mille. – jww

13

È un'affermazione statica sul tipo funzione prima del getto, fornendo un cast type-safe.

Da C11 (n1570) 6.5.15 (dalla sezione vincoli)

Operatore condizionale

(3), una delle seguenti deve possedere per il secondo e terzo operandi:

  • [omissione di contenuto non puntatore]
  • entrambi gli operandi sono puntatori a versioni qualificate o non qualificate di comp tipi atipici;
  • un operando è un puntatore e l'altro è una costante di puntatore nullo; oppure
  • un operando è un puntatore a un tipo di oggetto e l'altro è un puntatore a una versione qualificata o non qualificata di void.

Il terzo operando è un puntatore a una funzione (quindi l'ultimo punto non si applica), quindi questo compila (senza avviso) solo se sia p è un puntatore nullo costante o di un tipo compatibile con void (*)(type) per l'ultima macro (dopo la conversione in un puntatore di funzione, se p è un designatore di funzione).