2012-07-18 8 views
5

Attualmente sto convertendo un codice OpenCV da C++ a Java. Non posso usare JavaCV, poiché abbiamo bisogno della conversione in Java nativo, non in un JNA. A un certo punto nel codice, ottengo la seguente assegnazione:Come funziona l'operatore unario negativo sui booleani in C++?

dst[x] = (uchar)(-(kHit >= kForeground)); 

Dove dst è uchar*, kHit e kForeground sono int s.

Non riesco a trovare nulla su come funziona, e Java non lo riconoscerà come un'operazione. Esiste un'operazione su queste due variabili in un altro punto del codice e memorizza uno di due valori: 255 o 0.

Il codice in questione viene da opencv/video/src/bgfg_gaussmix.cpp.

risposta

7

In C++ un'espressione booleana produce uno di due valori: 0 o 1. Quando si applica l'unario meno - al risultato, si ottiene 0 o -1. Quando si reinterpreta -1 come uchar, si ottiene 255.

È possibile convertire questa espressione per Java con un condizionale:

dst[x] = (kHit >= kForeground) ? 255 : 0; 

A causa della ramificazione, che non sta per essere veloce come quella originale. C'è poco che si possa fare per quanto riguarda la velocità di esso, tuttavia, poiché Java non ha la capacità di reinterpretare i valori booleani come valori numerici.

+0

Questo ha senso, ed è qualcosa che avrei potuto facilmente provare e scoprire da solo. Grazie per averlo indicato in modo così conciso. – Wraith967

+0

Tecnicamente l'espressione booleana produce 'true' o' false', che quando viene promosso ad un 'int' otterrà i valori' 1' o '0'. –

6

kHit >= kForeground rendimenti sia true o false, che in C++ sorta di mezzi 1 o 0. Il segno meno anteriore lo trasforma in -1 o 0. Il cast a uchar ((uchar)) restituisce 0 per 0 e include per il numero di serie -1.

Seguendo il commento di Konrad, sono anche scettico sul fatto che sia ben definito. È ben definito, ma è ancora una parte terribile del codice in termini di leggibilità. :)

+3

Su * alcuni * compilatore/macchina. Questo codice è inutilmente non vendibile. –

+2

Lo standard C++ non specifica esplicitamente i tipi non firmati per comportarsi come se fossero twos-complemento, quindi questo dovrebbe essere ben definito (come vero == 1 e falso == 0 è anche ben definito)? –

+0

@KonradRudolph: lo standard specifica che 'Un valore di tipo bool può essere convertito in un valore pr di tipo int, con false che diventano zero e true che diventa uno. [Conv.prom], e che' Se il tipo di destinazione è senza segno, il valore risultante è il numero intero senza segno congruente al numero intero sorgente (modulo 2n dove n è il numero di bit usati per rappresentare il tipo senza segno) '[conv.integral]. Quindi penso che questo codice sia effettivamente ben definito e portatile tra i compilatori conformi. –

1

Ciò che fondamentalmente segue:

kHit >= kForeground 

è un'espressione di tipo bool

-(kHit >= kForeground) 

converte questo bool in un int (basato su true==1 e false==0) e nega, che risulta in true==-1 e false==0.

Questo è quindi convertito in uchar, che risulta in -1==255 e 0==0.

Si noti che sebbene sembrino utilizzare i dettagli di implementazione sottostanti dei numeri, tutte quelle conversioni sono garantite dagli standard C++ e C, poiché i numeri non firmati negativi vengono specificati per comportarsi in base al complemento a due.

Ma se Java non supporta questo, è sempre possibile sostituirlo con un incarico condizionale:

dst[x] = (kHit>=kForeground) ? 255 : 0; 
1

L'espressione (kHit >= kForeground) produce un valore booleano che ha valore true o false. Quando viene applicato l'unario -, lo bool viene promosso a int e la conversione produce 1 per true o 0 per false. Dopo la promozione, il segno viene modificato in -1 o 0 e quindi viene convertito in uchar dal cast esterno.

Si noti che il bit importante di informazioni è che l'unario operator- non viene applicato a un valore booleano, ma il valore booleano viene convertito in int e viene quindi applicato. Che possono essere testati con un po 'di magia modello:

template <typename T, typename U> 
struct same_type { 
    static const bool value = false; 
}; 
template <typename T> 
struct same_type<T,T> { 
    static const bool value = true; 
}; 
template <typename T> 
void f(T value) { 
    std::cout << "Is int? " << std::boolalpha << same_type<T, int>::value << "\n"; 
    std::cout << "Is bool? " << same_type<T, bool>::value << "\n"; 
} 
int main() { 
    f(-true); 
} 

Il modello f verifica il tipo dell'argomento passato contro int e bool utilizzando i same_type modelli di cui sopra (abbastanza banali da capire). Se chiamiamo il modello f con -true come tipo di argomento la deduzione imposterà T come il tipo dell'espressione -true. Se esegui il programma, vedrai che stampa Is int? true\nIs bool? false.

+0

Buona risposta, ma penso che potresti rendere molto più chiara l'illustrazione della conversione integrale con due sovraccarichi di base. 'void f (int) {cout <<" int \ n "; } void f (bool) {cout << "bool \ n"; } f (true); f (-true); ' –

+0

@LucTouraille: Immagino, ho appena avuto quel [martello] (http://en.wikipedia.org/wiki/Law_of_the_instrument) nella mia cassetta degli attrezzi (ora che ci penso c'è un semplice approccio: 'modello void print_type (T); print_type (-true);' ('print_type' dichiarato, non definito) indicherà il tipo nel messaggio del linker –

Problemi correlati