elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Trabajando con las ramas de git (tercera parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  ENIGMA SOBRE C . Terminación de programas
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] 2 Ir Abajo Respuesta Imprimir
Autor Tema: ENIGMA SOBRE C . Terminación de programas  (Leído 4,407 veces)
dijsktra

Desconectado Desconectado

Mensajes: 110


Mr Edsger Dijsktra (Tribute to)


Ver Perfil
ENIGMA SOBRE C . Terminación de programas
« en: 28 Febrero 2019, 13:57 pm »

Hola!

En una facultad de Madrid me he encontrado pinchado en el panel este original reto...
Está en inglés, pero creo que se entiende...
  • El primer problema pide demostrar que el programa dado acaba
  • El segundo dice que cuando acabe, el sistema sacará la llamada correspondiente al assert.  :o :o


Alguna propuesta ? :o :o :o


« Última modificación: 8 Marzo 2019, 15:22 pm por dijsktra » En línea

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #1 en: 28 Febrero 2019, 19:14 pm »

El segundo ejemplo no debería parar y el assert(1) no debería fallar.


En línea

EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.072



Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #2 en: 28 Febrero 2019, 19:43 pm »

Saludos,

- El FOR requiere de ( Sentencia; Condicion; Sentencia ), tengo entendido de que las Sentencias pueden quedar vacías, lo he visto mucho en javascript.

-- En el primer caso es un bucle que no se cumple, la condición es 0 o FALSE

-- En el segundo caso el bucle en infinito y nunca llega a ejecutarse el assert(1)

- Entonces pienso que el libro se refiere a un problema de compilación, pero mi compilador MinGW no me ha dado ningún problema. Algo así como decir que se está importando tal cosa y no se está usando, o se ha detectado un bucle infinito, o se ha detectado una sentencia de código ( assert(1) ) que nunca se ejecutará debido x razón, etc.

---

- También me parece sospechoso ese ; al final del FOR, supongo que dependiendo del tema del libro, podría estar explicando que el ; da por finalizado el Bucle en esa misma línea y no ejecuta nada más, es decir, ese FOR no tiene cuerpo a ejecutar:

Código
  1. for ( sentencia, condicion, sentencia ) ;
  2.  
  3. for ( sentencia, condicion, sentencia )
  4.  cuerpo a ejecutar
  5.  
  6. for ( sentencia, condicion, sentencia ) {
  7.  cuerpo a ejecutar
  8. }
  9.  
  10. for ( sentencia, condicion, sentencia ) ;
  11.  esta sentencia no pertenece al FOR y es independiente
  12.  
  13. for ( sentencia, condicion, sentencia ) ; {
  14.  esta sentencia no pertenece al FOR y es independiente
  15. }
  16.  
« Última modificación: 28 Febrero 2019, 19:47 pm por EdePC » En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #3 en: 28 Febrero 2019, 21:18 pm »

Al primer ejemplo no le veo mucha complicación, un <for> se ejecuta mientras la condición (segundo campo del <for>) sea verdadera (1). Los campos de inicialización (primer campo) y actualización (tercer campo) pueden quedarse vacíos como es el caso aunque siempre se ha comentado que no es una buena práctica ya que en otros lenguajes no está permitido este uso.
Se ejecuta el <for> y como la condición es falsa (0) termina y sale.

En cambio, en el segundo ejemplo es todo lo contrario, el <for> no termina nunca ya que la condición es siempre verdadera (1) y como ya ha comentado EdePC, como el <for> acaba en punto y coma (;) la instrucción del <assert(1)> no se ejecutará nunca ya que no pertenece al cuerpo del <for> y este genera un bucle infinito.
En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
Loretz

Desconectado Desconectado

Mensajes: 117


Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #4 en: 28 Febrero 2019, 23:02 pm »

El primer caso a mí me parece lo mismo; para el segundo lo único que se me ocurre es que alguien ha estado jugando con <assert>, así que si yo también...

Código
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. #define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
  5.  
  6. #define assert(expression) (void)((!(expression)) || (mostrar(#expression, __FILENAME__, (unsigned)(__LINE__), __func__), 0))
  7.  
  8. #define for(a) while(0)
  9.  
  10. void mostrar(const char* message, const char* file, int line, const char* function)
  11. {
  12.    printf("%s: %s:%i: %s: Assertion \'%s\' failed\n", function, file, line, function, message);
  13. }
  14.  
  15. int main()
  16. {
  17.    for( ;1; );
  18.  
  19.    assert(1);
  20. }
En línea

dijsktra

Desconectado Desconectado

Mensajes: 110


Mr Edsger Dijsktra (Tribute to)


Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #5 en: 1 Marzo 2019, 09:37 am »

Chicos, gracias por vuestras repuestas.
  Loretz, muy buena tu exhibición, pero el ejercicio que propones no cumple lo que dice, porque YA es otro fichero fuente del que se propone...

Creo que hay que hacerlo sobre el mismo contenido del original y lo que me choca más... se supone que no vale argûir "Alguien ha jugado con el assert, pues yo también...", porque el sistema ha de ser compatible ANSI-C/ISO-C, o sea, el assert tiene que hacer lo que se espera de él...

Os digo mis progresos:
  • Es un absurdo esperar a que acabe un programa que no acaba. Todo el mundo está de acuerdo en que el bucle es infinito.
  • Es un absurdo esperar que assert falle cuando el parámetro sea 1, ya que sólo falla cuando vale 0, según el ANSI-C/ISO-C

No hay manera de relacionar estos absurdos entre sí? Me huelo que "por aquí va la tostada", rollo lógica....

En cuanto tenga algo os lo paso...


El primer caso a mí me parece lo mismo; para el segundo lo único que se me ocurre es que alguien ha estado jugando con <assert>, así que si yo también...

Código
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. #define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
  5.  
  6. #define assert(expression) (void)((!(expression)) || (mostrar(#expression, __FILENAME__, (unsigned)(__LINE__), __func__), 0))
  7.  
  8. #define for(a) while(0)
  9. ...
  10.  
« Última modificación: 1 Marzo 2019, 10:28 am por dijsktra » En línea

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)
Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.357


Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #6 en: 2 Marzo 2019, 10:00 am »

Esto son temas de sobra conocidos en teoría de compiladores.

El primer tema a considerar: Los bucles infinitos versa que si el incremento es 0 y el valor inicial es igual al valor final, no es un bucle infitio, en otro caso si:
       bucle infinito = ((inc = 0) and (inicio <> final))
...y si el cuerpo está vacío (como es el caso), o no existe dentro una sentencia de escape del bucle (si existe, deberá examinarse también). Lógicamente en tiempo de compilación...
       Por eso no se cumple en el primer caso y sí en el segundo.

Los bucles infinitos de este modo, en realidad pueden ser tomados como bucles incondicionales (tipo do...loop) y han sido la solución para lenguajes en los que no existen otro tipo de bucles que no sean condicionados por una expresión aritmética pero que si admiten una sentencia de salida del mismo controlados por algún 'if then else'.

El segundo tema a considerar: En teoría de compiladores se trata en la optimización de código, para eliminar código redundante o código inaccesible. Código inaccesible es aquel que nunca se va a ejecutar, caso por ejemplo como:

Código:
int x = 20
si x = 0
    ...
fin si
El compilador detectará que si a x se el asigna la constante 20, no puede tener de inmediato la contante 0, luego todo el código dentro del condicional incluído el condicional, puede ser omitido.
Piénsese que los condicionales 'if then', a efectos prácticos pueden considerarse bucles de 0 ó 1 ciclos.

Desde el momento en que entras en un bucle infinito, el código que venga detrás se vuelve inaccesible, que es lo que pasa en el segundo ejemplo.
En línea

dijsktra

Desconectado Desconectado

Mensajes: 110


Mr Edsger Dijsktra (Tribute to)


Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #7 en: 4 Marzo 2019, 10:10 am »

Hola NEBIRE
...

El primer tema a considerar: Los bucles infinitos versa que si el incremento es 0 y el valor inicial es igual al valor final, no es un bucle infitio, en otro caso si:
       bucle infinito = ((inc = 0) and (inicio <> final))
...y si el cuerpo está vacío (como es el caso), o no existe dentro una sentencia de escape del bucle (si existe, deberá examinarse también). Lógicamente en tiempo de compilación...
       Por eso no se cumple en el primer caso y sí en el segundo.
...
Esta propuesta no vale. Estás describiendo un caso muy partícular de bucles "for", los que se parecen /ajustan al patrón de Pascal
Código:
for < variable-name > := < initial_value > to [down to] < final_value > do 
   S;

Pero en el caso de C que se da, que variables hay?, cual es el valor inicial y/o final?
En C, el bucle for es tan versátil/expresivo como el while.

EScrito de otro modo, en el primer caso hay que explicar por qué el bucle C, acaba:

Código
  1. while (0) ;

Aqui no hay duda de que no hay valores iniciales, ni finales.... Solo constantes.



« Última modificación: 4 Marzo 2019, 10:29 am por dijsktra » En línea

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #8 en: 4 Marzo 2019, 12:52 pm »

Yo lo veo una proposición más filosófica que práctica.
Ya de por sí la premisa, sobre el segundo fuentes, es falsa porque ese bucle no terminan nunca, al tener en la condición un 1 y por tanto siempre será cierta. Pero en ese mismo fuente se podría considerar que 1 es falso ya que ese valor detiene el bucle y, además, hace saltar al assert. Y ya que el 1 del for y el 1 del assert son diferentes por ser dos objetos diferentes pero con el mismo símbolo (es decir, no son una posición de memoria que por alguna razón ajena al programa ha cambiado, sino que realmente es 1) entonces 1 es 0.
En ese supuesto, imposible por otra parte, sí que se llegaría a la solución propuesta.
En línea

dijsktra

Desconectado Desconectado

Mensajes: 110


Mr Edsger Dijsktra (Tribute to)


Ver Perfil
Re: ENIGMA SOBRE C . Terminación de programas
« Respuesta #9 en: 4 Marzo 2019, 12:57 pm »

Exacto MAFUS! Lo has clavado!

Yo lo veo una proposición más filosófica que práctica.
Ya de por sí la premisa, sobre el segundo fuentes, es falsa porque ese bucle no terminan nunca, al tener en la condición un 1 y por tanto siempre será cierta. Pero en ese mismo fuente se podría considerar que 1 es falso ya que ese valor detiene el bucle y, además, hace saltar al assert. ...
En ese supuesto, imposible por otra parte, sí que se llegaría a la solución propuesta.

Bueno, creo que ya lo tengo, chicos. Me han ayudado un poco por ahí... Y cuando lo entiendes, es una pura broma.... :D :D :D :D

La cuestión tiene que ver no tanto con C, como con dos aspectos de la algoritmia:
  • la terminación de un programa
  • la corrección parcial, que nos dice que si acaba, (notese la cursiva) entonces el programa computa lo que se espera de él.  

Las dos cuestiones son ciertas. Empiezo por la más extraña, la segunda, la del bucle infinito.
  • Según el estandar ANSI-C, asssert solo falla cuando la evaluación del parámetro da 0 (false). En nuestro caso, assert(1), cuando 1==0, lo que es un absurdo  :o :o
  • Según el estandar ANSI-C, el bucle acaba cuando la parte del discriminante da 0 (false) . En nuestro for( ; 1; ), caso, cuando 1==0 , (en terminos prácticos, nunca)   :D :D
  • O sea, que cuando el bucle acabe, (no dice que acabe, dice que cuando acabe, esto es importante!) se cumplirá   1==0, lo que es la condición para que assert(1) falle.  :D :D :D :D

 :D :D :D :D Esta bien el enigma... A nadie engaña por decir que esperando lo suficiente, el assert(1) fallará... Eso sí, tiene que esperar lo suficiente, por los siglos de los siglos...

Formalmente, pura lógica...
Código:

(Short proof)
     1=0 |= 1=0  q.e.d  

(Full proof)

Let Post Q:1=0 .

Then we have to proof that

  { I } for( ; 1 ; ) { Q } (Partial correctness, no matter I)

  1. { I } skip {I}  SKIP
  2. I and 1=1 -> I (Logic, stronger antecedent )
  3. { I and 1=1 } skip { I } STREN(1,2)
  4. I and 1=0 -> 1=0 (Logic, false (or stronger) antecedent)
  5. { I } for( ; 1 ; ) { 1=0 }  WHILE(3,4)

  q.e.d

Remark: ANSI-C states
     * assert(1) call does fail when 1=0 ("never")
     * loop for( ;1;) does end when 1=0 ("never" ;-D)
     * empty loop's body is skip.

El primer problema, que todos veíamos que acababa, también es parecido...pero ahora si nos interesa demostrar que efectivamente acaba, y nos da igual lo que pase al acabar.

En los libros de algoritmia se dice que para que un bucle acabe (terminación) tenemos que idear una quota definida positiva en el punto antes de evaluar la condición de salida  (un invariante). Como no hay variables, escogemos como quota C(n)=0... Esta quota tiene que disminuir cada vuelta, es decir 0 < 0, lo que es un absurdo.
Como va a disminuir cada vuelta, si nunca entra? Bueno, seg'un el estandar ANSI entra cuando la evualuación de la guarda es  distinta de 0, nuestro caso for( ; 0 ; ) , cuando 0!=0 (o sea nunca).

El resultado es que cuando 0!=0 entonces ocurrirá que 0 < 0. No dice que 0!=0, sino que cuando 0!=0, absurdo, entonces 0<0 (otro absurdo). Genial!  Pura lógica.

Código:

(Short proof)

   0!=0 |= 0 < 0   q.e.d.

(Full proof)

Let C()=0 >= 0 positively defined, i.e.

      I -> 0 >= 0  (no matter I)
      
Then we have to proof

     { I and 0!=0 and 0=0 } skip { 0 < 0} (Quota indeed decreases)

    1. { 0 < 0 } skip { 0 < 0 } (SKIP)
    2. I and 0!=0 and 0=0 -> 0 < 0  (Logic, false antecedent)
    3. { I and 0!=0 and 0=0 } skip { 0 < 0 } (STRENG(2,1))

    q.e.d

Remark :   * ANSI-C states the loop is entered
           when 0!=0, i.e. "never" ;-D
  * empty loop's body is "skip"





« Última modificación: 4 Marzo 2019, 17:55 pm por dijsktra » En línea

Si la depuración es el proceso de eliminar fallos en el software, entonces programar debe ser el proceso de ponerlos dentro. (Edsger Dijsktra)
Páginas: [1] 2 Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
terminacion .ISO « 1 2 »
Multimedia
kai 11 7,094 Último mensaje 16 Junio 2004, 18:50 pm
por Songoku
Como paso un video de terminacion .avi a .mpg??
Multimedia
Amras 3 1,919 Último mensaje 8 Septiembre 2006, 04:59 am
por theshadow
Craquear md5 con terminación numérica
Hacking
shargon 6 4,013 Último mensaje 8 Mayo 2014, 19:39 pm
por toxeek
REY ENIGMA
Foro Libre
Minusfour_cierralo_o_baneamefull 3 3,910 Último mensaje 3 Noviembre 2021, 21:15 pm
por Minusfour_cierralo_o_baneamefull
Enigma Protec
Ingeniería Inversa
virtualcyclops 0 1,977 Último mensaje 17 Mayo 2022, 04:35 am
por virtualcyclops
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines