2012-07-18 20 views
5

Actualmente estoy convirtiendo algunos códigos OpenCV de C++ a Java. No puedo usar JavaCV, ya que necesitamos la conversión en Java nativo, no en JNA. En un momento en el código, me sale el siguiente asignación:¿Cómo funciona el operador unario negativo en booleanos en C++?

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

Dónde dst es uchar*, kHit y kForeground son int s.

No he podido encontrar nada sobre cómo funciona esto, y Java no lo reconocerá como una operación. Hay una operación en estas dos variables en otro punto del código, y almacena uno de dos valores: 255 o 0.

El código en cuestión proviene de opencv/video/src/bgfg_gaussmix.cpp.

Respuesta

7

En C++ una expresión booleana produce uno de dos valores: 0 o 1. Cuando aplica el unario menos - al resultado, obtiene 0 o -1. Cuando vuelve a interpretar -1 como uchar, obtiene 255.

Puede convertir esta expresión para Java con un condicional:

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

Debido a la ramificación, que no va a ser tan rápido como el original. Sin embargo, es poco lo que puede hacer con respecto a la velocidad, ya que Java carece de la capacidad para volver a interpretar los valores booleanos como numéricos.

+0

Esto tiene sentido, y es algo que podría haber probado y descubierto muy fácilmente por mi cuenta. Gracias por señalarlo de manera concisa. – Wraith967

+0

Técnicamente, la expresión booleana produce 'true' o' false', que cuando se promociona a 'int' obtendrá los valores' 1' o '0'. –

6

kHit >= kForeground devuelve o true o false, que en C++ tipo de medios 1 o 0. El signo menos al frente lo transforma en -1 o 0. La conversión a uchar ((uchar)) devuelve 0 para 0 y se ajusta a 255 para la negativa -1.

Siguiendo el comentario de Konrad, también soy escéptico de que esté bien definido. Está bien definido, pero sigue siendo un pedazo de código terrible en términos de legibilidad. :)

+3

En * algún * compilador/máquina. Este código es innecesariamente inportable. –

+2

¿El estándar de C++ no especifica explícitamente los tipos sin signo para comportarse como complemento a dos, por lo que debería estar bien definido (como verdadero == 1 y falso == 0 también está bien definido)? –

+0

@KonradRudolph: el estándar especifica que 'Un prvalue de tipo bool se puede convertir a un prvalue de tipo int, con falso convirtiéndose en cero y verdadero convirtiéndose en uno. [Conv.prom], y que' Si el tipo de destino no está firmado, el valor resultante es el entero menos sin signo congruente con el entero de origen (módulo 2n donde n es el número de bits utilizados para representar el tipo sin signo) '[conv.integral]. Así que creo que este código en realidad está bien definido y es portátil en los compiladores compatibles. –

1

Lo que hace básicamente es el siguiente:

kHit >= kForeground 

es una expresión de tipo bool

-(kHit >= kForeground) 

convierte esta bool en un int (basado en true==1 y false==0) y la niega, lo que se traduce en true==-1 y false==0.

Esto se convierte en uchar, lo que da como resultado -1==255 y 0==0.

Cabe señalar que, aunque parezca que utiliza los detalles de implementación subyacentes de los números, todas esas conversiones están garantizadas por los estándares C++ y C, ya que los números negativos sin signo se comportan de dos en dos.

Pero si Java no soporta esto, siempre se puede reemplazar por una asignación condicional:

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

La expresión (kHit >= kForeground) se obtiene un valor booleano que tiene valor true o false. Cuando se aplica el - único, el bool se promociona a int, y la conversión produce 1 para true o 0 para false. Después de la promoción, el signo se cambia a -1 o 0 y luego se convierte a uchar por el modelo externo.

Tenga en cuenta que la información importante es que el operator- único no se aplica a un booleano, pero el booleano se convierte a int y luego se aplica. Que se puede probar con un poco de magia plantilla:

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); 
} 

La plantilla f pone a prueba el tipo del argumento pasado contra int y bool mediante el uso de las plantillas anteriores same_type (lo suficiente para entender triviales). Si llamamos a la plantilla f con -true como tipo de argumento, la deducción establecerá T como el tipo de la expresión -true. Si ejecuta el programa, verá que imprime Is int? true\nIs bool? false.

+0

Buena respuesta, pero creo que podría hacer la ilustración de la conversión integral mucho más clara con dos sobrecargas básicas. 'void f (int) {cout <<" int \ n "; } void f (bool) {cout << "bool \ n"; } f (verdadero); f (-true); ' –

+0

@LucTouraille: Supongo que acabo de tener ese [martillo] (http://en.wikipedia.org/wiki/Law_of_the_instrument) en mi caja de herramientas (ahora que lo pienso hay un simple aproximación: 'template void print_type (T); print_type (-true);' ('print_type' declarado, no definido) le dirá el tipo en el mensaje del enlazador –

Cuestiones relacionadas