2008-10-07 36 views
15

Hoy en el trabajo nos encontramos con el siguiente código (algunos de ustedes podrían reconocerlo):¿Cuál es el código de C++ más difícil de entender que conoces?

#define GET_VAL(val, type) \ 
    {             \ 
     ASSERT((pIP + sizeof(type)) <= pMethodEnd); \ 
     val = (*((type *&)(pIP))++);     \ 
    } 

Básicamente tenemos una matriz de bytes y un puntero. La macro devuelve una referencia a una variable de tipo y avanza el puntero hasta el final de esa variable.

Me recordó las varias veces que necesitaba "pensar como un analizador sintáctico" para entender el código C++.

¿Conoces otros ejemplos de código que hicieron que te detengas y lo leyeras varias veces hasta que lograste comprender lo que se suponía que debía hacer?

+3

No - Escribí esta pregunta para que podamos mostrar formas interesantes y confusas de usar C++. Entonces podemos aprender de esos ejemplos. –

+4

Estos comentarios sobre las preguntas que se cierran son ridículos. – Terminus

+2

En cualquier caso, este debería ser wiki de la comunidad. –

Respuesta

29

La inversa aplicación de la raíz cuadrada en Quake 3:

float InvSqrt (float x){ 
    float xhalf = 0.5f*x; 
    int i = *(int*)&x; 
    i = 0x5f3759df - (i>>1); 
    x = *(float*)&i; 
    x = x*(1.5f - xhalf*x*x); 
    return x; 
} 

Actualizar: How this works (gracias ryan_s)

+1

No se olvide de vincular el trabajo de Chris Lamont para la gran explicación de cómo funciona esta locura. http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf –

2

C, pero presente en C++, creo que el operador coma realmente ofusca código, aprovechar esta ...

ihi = y[0]>y[1] ? (inhi=1,0) : (inhi=0,1); 

Conciso y bastante elegante, pero muy fácil pasar por alto o malinterpretar.

+2

Para mí, este código es un ejemplo perfecto de "Solo porque puedes hacer algo, no significa que debas". Está ordenado porque está en una línea, pero si se extendiera más sería mucho más comprensible para alguien que lo mire por primera vez. No es que no sea un buen ejemplo. :) – Colen

9

Esto es bien conocido, pero todavía de forma impresionante para intercambiar dos enteros sin crear variable TEMP:

// a^=b^=a^=b;  // int a and int b will be swapped 
// Technically undefined behavior as variable may only 
// be assined once within the same statement. 
// 
// But this can be written correctly like this. 
// Which still looks cool and unreadable ;-) 

a^=b; 
b^=a; 
a^=b; 
+2

único problema es que este es un comportamiento técnicamente indefinido debido a las reglas de punto de secuencia. use "a^= b; b^= a; a^= b;" en lugar. –

+0

incorrecto es correcto. El orden de operación está perfectamente definido de derecha a izquierda en este caso. Lea el estándar, – Terminus

+3

@ Terminus: Usted está de hecho equivocado. Asignar a una variable más de una vez en una declaración es un comportamiento indefinido. Para evitar esto, necesita usar el ';' para separarlos en diferentes declaraciones. –

0

cambios binarios me confunde todo el tiempo:

Un ejemplo de java.util.concurrent.ConcurrentHashMap :

retorno ((h < < 7) - h + (h >>> 9) + (h >>> 17))

+3

¿Por qué se votó? Esto es Java, pero la pregunta es sobre C++. – finnw

25

Esto fue en rojo DIT recientemente http://www.eelis.net/C++/analogliterals.xhtml

assert((o-----o 
     |  ! 
     !  ! 
     !  ! 
     !  ! 
     o-----o).area == (o---------o 
          |   ! 
          !   ! 
          o---------o).area); 
+0

esto es una tautología. – Haoest

+2

¡Ahora * este * es por qué amo C++! –

+0

El enlace ahora está roto :( –

10
unsigned int reverse(register unsigned int x) 
{ 
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 
return((x >> 16) | (x << 16)); 
} 

invierte el orden de los bits en un int.

+0

Si esto hubiera sido un código de truco inteligente, entonces +1. –

+0

En realidad, no es muy difícil entender lo que hace debido al nombre de la función. Es _cómo_ está hecho eso es complicado. – einpoklum

+0

Esto es un código C algo más oscuro. –

-3

Voto por una metaprogramación de plantillas de black-magic-hackerish (lamentablemente no tengo ninguna a mano para publicarla).

14

dispositivo de Duff (http://en.wikipedia.org/wiki/Duff%27s_device) dame pesadillas:

strcpy(to, from, count) 
char *to, *from; 
int count; 
{ 
    int n = (count + 7)/8; 
    switch (count % 8) { 
    case 0: do { *to = *from++; 
    case 7:  *to = *from++; 
    case 6:  *to = *from++; 
    case 5:  *to = *from++; 
    case 4:  *to = *from++; 
    case 3:  *to = *from++; 
    case 2:  *to = *from++; 
    case 1:  *to = *from++; 
       } while (--n > 0); 
    } 
} 
+0

Siempre he encontrado que el dispositivo de Duff es bastante intuitivo, simplemente tiene sentido. Después de superar la extraña sintaxis del ciclo que está rodando, o desenrollar quizás :) –

+0

Creo que esto es más fácil de entender si ha programado el ensamblaje que si proviene de un fondo que no es el ensamblado. – Skizz

6

más cosas Boost - la metaprogramming plantilla es bastante malo, pero cuando se toma en cuenta las soluciones necesarias para conseguir que funcione en algunos compiladores (* coughborlandcough *), se pone bastante ridículo. Solo trata de entender Boost.Bind. Sólo inténtalo.

Cuestiones relacionadas