while tutorial sentencia salir que programacion else ejemplos como ciclo c function-pointers

tutorial - ¿Cómo funciona el código C que imprime de 1 a 1000 sin bucles o declaraciones condicionales?



sentencia if java (2)

He encontrado código C que imprime de 1 a 1000 sin bucles o condicionales : pero no entiendo cómo funciona. ¿Alguien puede revisar el código y explicar cada línea?

#include <stdio.h> #include <stdlib.h> void main(int j) { printf("%d/n", j); (&main + (&exit - &main)*(j/1000))(j+1); }


Nunca escribas código así.

Para j<1000 , j/1000 es cero (división entera). Asi que:

(&main + (&exit - &main)*(j/1000))(j+1);

es equivalente a:

(&main + (&exit - &main)*0)(j+1);

Cual es:

(&main)(j+1);

Que llama main con j+1 .

Si j == 1000 , entonces las mismas líneas salen como:

(&main + (&exit - &main)*1)(j+1);

Lo que se reduce a

(&exit)(j+1);

Que es exit(j+1) y abandona el programa.

(&exit)(j+1) y exit(j+1) son esencialmente lo mismo - citando C99 §6.3.2.1 / 4:

Un designador de función es una expresión que tiene un tipo de función. Excepto cuando es el operando del operador sizeof o el operador unario , un designador de función con tipo " function returning type " se convierte a una expresión que tiene el tipo " puntero a función que devuelve type ".

exit es un designador de función. Incluso sin el operador unario & address-of, se trata como un puntero para funcionar. (The & just lo hace explícito.)

Y las llamadas a funciones se describen en §6.5.2.2 / 1 y siguientes:

La expresión que denota la función llamada tendrá un puntero de tipo para que la función devuelva vacía o devuelva un tipo de objeto que no sea un tipo de matriz.

Así que exit(j+1) funciona debido a la conversión automática del tipo de función a un tipo de puntero a función, y (&exit)(j+1) funciona con una conversión explícita a un tipo de puntero a función .

Dicho esto, el código anterior no es conforme ( main toma dos argumentos o ninguno en absoluto), y &exit - &main es, creo, indefinido de acuerdo con §6.5.6 / 9:

Cuando se restan dos punteros, ambos señalarán elementos del mismo objeto de matriz , o uno más allá del último elemento del objeto de matriz; ...

La adición (&main + ...) sería válida en sí misma y podría usarse si la cantidad añadida fuera cero, ya que en el §6.5.6 / 7 dice:

Para los propósitos de estos operadores, un puntero a un objeto que no es un elemento de una matriz se comporta de la misma manera que un puntero al primer elemento de una matriz de longitud uno con el tipo de objeto como su tipo de elemento.

Por lo tanto, agregar cero a &main sería correcto (pero no demasiado útil).


Utiliza la recursividad, la aritmética del puntero y explota el comportamiento de redondeo de la división entera.

El término j/1000 redondea a 0 para todo j < 1000 ; una vez que j alcanza 1000, se evalúa a 1.

Ahora, si tiene a + (b - a) * n , donde n es 0 o 1, termina con a si n == 0 , b si n == 1 . Usando &main (la dirección de main() ) y &exit para b , el término (&main + (&exit - &main) * (j/1000)) regresa &main cuando j está por debajo de 1000, &exit contrario. El puntero a la función resultante se alimenta con el argumento j+1 .

Toda esta construcción da como resultado un comportamiento recursivo: mientras que j está por debajo de 1000, la main llama recursivamente; cuando j alcanza 1000, llama a exit lugar, haciendo que el programa salga con el código de salida 1001 (que está algo sucio, pero funciona).