我不是一个C程序员,所以我意识到我有点不知所措。
如何定位此错误发生的位置并确定它是什么?在我看来,这是make命令的相关输出。
gmake --debug=jv
. . .
Putting child 0x8006e6600 (/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib/libaubit4gl-1.5_3.so) PID 77727 on the chain.
Live child 0x8006e6600 (/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib/libaubit4gl-1.5_3.so) PID 77727
/usr/local/bin/ld: keys.o:/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/incl/a4gl_libaubit4gl.h:1026: multiple definition of `abort_pressed'; fglwrap.o:(.bss+0xe0): first defined here
/usr/local/bin/ld: report.o: in function `A4GL_internal_open_report_file':
/usr/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib/libaubit4gl/report.c:764: warning: warning: tmpnam() possibly used unsafely; consider using mkstemp()
collect2: error: ld returned 1 exit status
Reaping losing child 0x8006e6600 PID 77727
gmake[2]: *** [Makefile:211: /home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib/libaubit4gl-1.5_3.so] Error 1
Removing child 0x8006e6600 PID 77727 from chain.
gmake[2]: Leaving directory '/usr/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib/libaubit4gl'
Reaping losing child 0x8006d2960 PID 77684
gmake[1]: *** [Makefile:276: libaubit4gl-1.5_3.so] Error 2
Removing child 0x8006d2960 PID 77684 from chain.
gmake[1]: Leaving directory '/usr/home/byrnejb_hll/Projects/AB4-1/aubit4glsrc/lib'
Reaping losing child 0x8006e4200 PID 77600
gmake: *** [Makefile:285: corecompile] Error 2
Removing child 0x8006e4200 PID 77600 from chain.
中的代码/lib/libaubit4gl.h是:
1024 #ifdef OBJECTMODULE$
1025 char opts[100][80];^I^I/*menu options */$
1026 int abort_pressed;$
1027 int relxedit = 0, relyedit = 0;$
1028 int aborted;$
1029 long time_offset = 0;$
1030 int week_no = -1;$
1031 struct s_form_attr std_dbscr;$
1032 #else$
1033 extern char opts[10][80];^I/*menu options */$
1034 extern int abort_pressed;$
1035 extern int relxedit, relyedit;$
1036 extern int aborted;$
1037 extern long time_offset;$
1038 extern int week_no;$
1039 dll_import struct s_form_attr std_dbscr;$
1040 #endif$
这是唯一提到abort_pressed
的地方。
fglwrap.c中的代码,也是唯一使用abort_pressed
的地方
1450 void$
1451 A4GL_def_quit (void)$
1452 {$
1453 #ifdef DEBUG$
1454 A4GL_debug ("FIXME: DEFER QUIT NOT IMPLEMENTED - Setting quit mode");$
1455 #endif$
1456 }$
1457 $
1458 int abort_pressed=0;$
1459 $
1460 /**$
1461 *$
1462 * @todo Describe function$
1463 */$
1464 void$
1465 A4GL_set_abort (int a)$
1466 {$
1467 #ifdef DEBUG$
1468 A4GL_debug ("set_abort called with %d", a);$
1469 #endif$
1470 abort_pressed = a;$
1471 }$
1472 $
正确的处理方法是什么?我正试图让一个曾经有效的程序重新运行,但我不是作者。
是的,所以看起来有多个";abort_ pressed";,其来源于a";。h〃;文件(头文件(。您不应该在.h文件中定义变量,只需声明它们即可。如果只包含一次.h文件,则可以避免此错误,但如果包含两次,则会出现此错误。
研究声明和定义之间的区别,并将定义从.h文件中移出。这是用C进行编码的最佳实践,即使您只需要在一个地方包含.h文件
至于发生的机制,编译器会将所有的.h文件复制并粘贴到任何包含它们的地方,即"#包括";header.h";将把header.h的所有代码粘贴到它写的任何地方。您可以多次声明,即声明一个函数";数学"-
void math(uint8_t val);
这样的东西可以随心所欲地多次写入代码,所以当它们被多次粘贴时,编译器不会感到困惑。然而,当你定义事物时,即定义一个变量";globalFlags";
uint32_t globalFlags;
这会混淆编译器,因为它正在创建一个值";globalFlags";在存储器中,可以通过关键字"来访问;globalFlags";。如果你试图创建第二个版本,编译器会感到困惑,因为它不知道要访问两个内存地址中的哪一个,因为";globalFlags";适用于两者。所以它抛出了一个错误,告诉你修复
这是遗留代码的常见问题。头文件或源文件都定义了一个只应声明的变量。
这来自于传统的UNIX链接模型;C最初并没有纯引用,也并没有extern
关键字,和当时的其他语言非常相似。
此外,放在上下文中讲,早期的C没有原型,结构成员名称没有名称空间(这就是为什么像BSD套接字这样的旧接口中的结构成员带有前缀(,而且基本上它不能区分彼此,但通过它们的名称,它在当时真的很原始。
因此,变量将被放在对象文件中的一个(特殊的(公共部分,而不是引用,任何重复的变量都将由链接器通过查看它来合并;如果我没有错的话,遵循FORTRAN使用的方法。
链接器仍然是它的一部分,它处理对象文件,并试图将公共部分中的符号解析为其他符号,最后剩下的所有符号都放在BSS中(未初始化/零数据(。
编译器会在这个公共部分中放入任何临时声明(即没有初始化程序值(。
GCC默认情况下对C采用这种方法,直到GCC 10,它改为与C++相同的方法,即将这些方法直接放入BSS中;公平的事情,因为:
- 30多年来,我们有更好的方法来处理这个问题
- 生成的机器代码并不总是最优的
- unix模型与C标准有点矛盾
- 无法判断重复的定义是故意的还是偶然的(所以这是一种糟糕的做法(
然而,GCC仍然可以编译未经修改的遗留代码,如果您不能或不愿修改它,只需切换即可:-fcommon
。