分配相同类型的值将不起作用(左值作为一元’和’操作数需要)

* EDIT xalloc相当于malloc,JMP_BUF定义为j​​mp_buf,SETJMP1定义为sigsetjmp如果是posix环境,setjmp则定义为。

在第一个文件中,我有以下代码

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

两个文件通过头文件共通

 extern JMP_BUF *thread_recovery_context; 

第三个文件有

 JMP_BUF long_eval_recovery_context, *thread_recovery_context; 

那么,当它们是相同的类型时,为什么会产生错误“左值作为一元’和’操作数’? 并且添加所述运营商并不会安抚它。

*编辑

实际上,我缩写它,因为我不认为其余的代码很重要,但完整的一行是

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

实际上,当我将它减少到只有thread_recovery_context = t它才有效。

但是,行

 switch(eval_round = SETJMP1(thread_recovery_context)) { 

也建立得很好。

是什么赋予了?

*编辑

似乎我将SETJMP1更改为setjmp,它构建得很好! 即使前者等同于后者。 任何人都知道为什么会这样?

*编辑我可以通过将表达式移动到单独的行来解决问题。 但我仍然想知道好奇心为什么它在宏观内部不起作用。

BTW :(从评论升级,因为这是正确的答案)

我不知道JMP_BUF / SETJMP1()是什么,但如果它是宏,则解析为jmp_buf: 无法分配 setjmp()的返回值,仅进行测试。 (这是标准C,否则:请相应标记您的问题)

背景:setjmp / longjmp()中涉及的机器对堆栈做了讨厌的事情(如果架构使用堆栈作为自动变量),如果你使用setjmp()中的返回值,则导致(实现定义或)未定义的行为分配。 所以:

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

是不正确的,而

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

这是正确的。 (假设#define SETJMP1(j) setjmp(j)是SETJMP1()的定义。 将方案添加到方案中甚至会使情况恶化。


更新:另一个潜在的问题可能是评估宏SETJMP1()函数式参数:

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

如果SETJMP1()计算其参数,这可能会做丑陋的事情,例如当SETJMP1()被定义为:

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

但这一切都取决于宏的定义,显然……

jmp_buf类型定义为数组类型:

ISO / IEC 9899:2011§7.13非本地跳转

声明的类型是:

 jmp_buf 

这是一种适合保存恢复调用环境所需信息的数组类型。

这极大地限制了您可以使用该类型的变量执行的操作。 最值得注意的是,类型不是(直接)可分配的,可以直接分配任何其他数组类型。

您可以将其包装在结构中并分配结构(但在调用setjmp()longjmp()sigsetjmp()siglongjmp()引用该成员)。

 struct AssignableJmpBuf { jmp_buf jump_buffer; }; 

您还应该观察到您使用setjmp()正在调用未定义的行为:

§7.13.2setjmp宏

¶4调用setjmp宏只能出现在以下某个上下文中:

  • 选择或迭代语句的整个控制表达式;
  • 关系或等于运算符的一个操作数与另一个操作数的整数常量表达式,结果表达式是选择或迭代语句的整个控制表达式;
  • 一元的操作数! 运算符,结果表达式是选择或迭代语句的整个控制表达式; 要么
  • 表达式语句的整个表达式(可能转换为void)。

5如果调用出现在任何其他上下文中,则行为未定义。

请注意,您无法可靠地捕获变量中setjmp()的结果; 这样做会根据C标准调用未定义的行为。 POSIX没有实质性的帮助:

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

请注意,一个可能的未定义行为是“它可以正常工作,因为任何理智的人都希望它能够工作”。 然而,从理解文件来看,理智的人会知道它不能得到保证。 例如,BSD(Mac OS X)手册页讨论了setjmp()作为一个函数(而不是像C标准规定的宏),并且不限制它可以明确使用的位置(仅通过引用’符合C标准’)。


SSCCE – 单个文件

我创建了一个单文件SSCCE( 简短,自包含,正确的示例 ),我认为这与您的代码是同构的。

 /* 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(); } 

代码需要在直接调用setjmp()和通过SETJMP1宏进行间接调用时使用*thread_recovery_context 。 他们需要同样的待遇并不令人意外; 这是预料之中的。 从评论和讨论中不清楚你所得到的是不同的。 请注意,由于您没有提供连贯的可编译代码,我们无法确定此代码是否与您同构; 实际上,由于您遇到编译器错误,我们必须推断出存在差异。

有一次,我得到了编译器警告(来自GCC 4.8.2的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 

您的错误消息不同; 我推断您使用的是不同的编译器,尽管可能是旧版本的GCC(可能是比GCC 4.6更旧的版本)。