la asignación de valores de tipos idénticos no funcionará (se requiere lvalue como operando ‘&’ único)

* EDIT xalloc es equivalente a malloc, JMP_BUF se define como jmp_buf, SETJMP1 se define a sigsetjmp si el entorno es posix, setjmp si no.

En el primer archivo, tengo el siguiente código

JMP_BUF *t; t = xalloc(sizeof(jmp_buf)); thread_recovery_context = t; 

Común a ambos archivos a través de un archivo de encabezado es

 extern JMP_BUF *thread_recovery_context; 

Y el tercer archivo tiene

 JMP_BUF long_eval_recovery_context, *thread_recovery_context; 

Entonces, ¿por qué procuraría esto el error “lvalue required as & ‘operand” unario, cuando son tipos idénticos? Y agregar dicho operador no lo apacigua.

*EDITAR

En realidad, lo abrevié, ya que no creía que el rest del código fuera importante, pero la línea completa era

 switch(eval_round = SETJMP1(thread_recovery_context = t)) { 

De hecho, cuando lo reduzco a solo thread_recovery_context = t funciona.

Sin embargo, la línea

 switch(eval_round = SETJMP1(thread_recovery_context)) { 

También construye bien.

¿Lo que da?

*EDITAR

Parece que si cambio SETJMP1 a setjmp, ¡se construye muy bien! A pesar de que el primero equivale a este último. Alguien sabe por qué sería eso?

* EDITAR Puedo solucionar el problema moviendo la expresión a una línea separada. Pero todavía me gustaría saber por curiosidad por qué no funcionó dentro de la macro.

Por cierto: (actualizado desde el comentario, ya que esta es la respuesta correcta)

No sé qué JMP_BUF / SETJMP1 () es / son, pero si son macros, resolviendo a jmp_buf: el valor de retorno de setjmp () no se puede asignar , solo se puede probar. (esto es para el estándar C, cuando no: por favor marque su pregunta como corresponda)

Antecedentes: la maquinaria involucrada en setjmp / longjmp () hace cosas desagradables a la stack (si la architecture usa una stack para variables automáticas), lo que resulta en (implementación definida o) un comportamiento indefinido si usa el valor de retorno de setjmp () en una asignación. Asi que:

 switch(eval_round = setjmp(thread_recovery_context)) { ...} 

es incorrecto, mientras

 switch(setjmp(thread_recovery_context)) {...} 

sería correcto (suponiendo que #define SETJMP1(j) setjmp(j) sea ​​la definición de SETJMP1 ()). La adición de la lectura al escenario incluso empeorará el caso.


ACTUALIZACIÓN: otro problema potencial podría ser la evaluación de los argumentos de estilo de función de la macro SETJMP1() :

 switch( SETJMP1(thread_recovery_context = t)) { ...} 

, lo que podría hacer cosas feas si SETJMP1() evalúa su argumento más de una vez, por ejemplo, cuando SETJMP1 () se definiría como:

 #define SETJMP1(j) (j) ? setjmp(j) : -1 

Pero todo depende de la definición de la macro, obviamente …

El tipo jmp_buf se define como un tipo de matriz:

ISO / IEC 9899: 2011 §7.13 Saltos no locales

El tipo declarado es:

 jmp_buf 

que es un tipo de matriz adecuado para mantener la información necesaria para restaurar un entorno de llamada.

Esto limita profundamente lo que puedes hacer con variables del tipo. En particular, el tipo no es (directamente) asignable, como tampoco se puede asignar ningún otro tipo de matriz directamente.

Podría envolverlo en una estructura y asignar la estructura (pero haga referencia al miembro en las llamadas a setjmp() , longjmp() , sigsetjmp() y siglongjmp() ).

 struct AssignableJmpBuf { jmp_buf jump_buffer; }; 

También debe observar que su uso de setjmp() está invocando un comportamiento indefinido:

§7.13.2 La macro setjmp

¶4 Una invocación de la macro setjmp aparecerá solo en uno de los siguientes contextos:

  • la expresión de control completa de una instrucción de selección o iteración;
  • un operando de un operador relacional o de igualdad con el otro operando una expresión constante constante, siendo la expresión resultante la expresión de control completa de una statement de selección o iteración;
  • El operando de un unario! el operador con la expresión resultante es la expresión de control completa de una instrucción de selección o iteración; o
  • la expresión completa de una statement de expresión (posiblemente, se anula).

5 Si la invocación aparece en cualquier otro contexto, el comportamiento no está definido.

Tenga en cuenta que no puede capturar el resultado de setjmp() en una variable de manera confiable; al hacerlo, se invoca un comportamiento indefinido de acuerdo con el estándar C. POSIX no ayuda materialmente:

  • setjmp()
  • longjmp()
  • sigsetjmp()
  • siglongjmp()

Tenga en cuenta que un posible comportamiento indefinido es “funciona como cualquier persona sensata espera que funcione”. Sin embargo, dicha gente sensata sabría, al leer la documentación, que no está garantizado. Por ejemplo, las páginas de manual de BSD (Mac OS X) analizan setjmp() como una función (no como una macro como prescribe el estándar C), y no colocan los límites donde se puede usar explícitamente (solo con referencia a ‘ se ajusta a la norma C ‘).


SSCCE – archivo único

He creado un solo archivo SSCCE ( Corto, Autocontenido, Ejemplo correcto ) que es, creo, isomorfo con su código.

 /* jumper.h */ #ifndef JUMPER_H_INCLUDED #define JUMPER_H_INCLUDED #include  typedef jmp_buf JMP_BUF; #define SETJMP1(x) setjmp(x) extern JMP_BUF *thread_recovery_context; #endif /* first.c */ //#include "jumper.h" #include  extern void function1(void); extern void function2(void); extern void function3(void); extern void working_function(void); static inline void *xalloc(size_t size) { void *vp = malloc(size); if (vp == 0) abort(); return vp; } void function1(void) { JMP_BUF *t = xalloc(sizeof(jmp_buf)); thread_recovery_context = t; } /* third.c */ //#include "jumper.h" #include  JMP_BUF long_eval_recovery_context, *thread_recovery_context; void function2(void) { int eval_round; switch (eval_round = SETJMP1(*thread_recovery_context)) { case 0: printf("%s(): First return\n", __func__); break; default: printf("%s(): Other return\n", __func__); break; } working_function(); } void function3(void) { int eval_round; switch (eval_round = setjmp(*thread_recovery_context)) { case 0: printf("%s(): First return\n", __func__); break; default: printf("%s(): Other return\n", __func__); break; } working_function(); } 

El código debe usar *thread_recovery_context tanto en la llamada directa a setjmp() como en la llamada indirecta a través de la macro SETJMP1 . Que requieran el mismo tratamiento no es una sorpresa; se espera No queda claro a partir de los comentarios y la discusión lo que tienes que es diferente. Tenga en cuenta que, dado que no ha presentado un código comstackble coherente, no podemos estar seguros de si este código es isomorfo para usted; de hecho, dado que está obteniendo errores de comstackción, debemos deducir que hay una diferencia.

En un momento dado, recibí las advertencias del comstackdor (de GCC 4.8.2 en un derivado de Ubuntu 12.04):

 sj.c: In function 'function3': sj.c:66:3: error: passing argument 1 of '_setjmp' from incompatible pointer type [-Werror] switch (eval_round = setjmp(thread_recovery_context)) ^ In file included from sj.c:5:0: /usr/include/setjmp.h:65:12: note: expected 'struct __jmp_buf_tag *' but argument is of type 'struct __jmp_buf_tag (*)[1]' extern int _setjmp (struct __jmp_buf_tag __env[1]) __THROWNL; ^ cc1: all warnings being treated as errors 

Tus mensajes de error fueron diferentes; Deduzco que está utilizando un comstackdor diferente, aunque probablemente sea una versión anterior de GCC (probablemente una versión anterior a GCC 4.6).