我正在编写一个名为nauty的程序。该程序使用规范函数名称getline,它也是标准GNU C库的一部分。
是否可以在编译时告诉GCC使用这个程序定义的函数?
答案 0 :(得分:6)
一个解决方案:
现在,您已在某些应用程序.h
文件中声明了该函数,如:
int getline(...); // the custon getline
将其更改为:
int application_getline(...); // the custon getline
#define getline application_getline
我认为应该这样做。它还将修复定义函数的.c
文件,假设它包含.h
文件。
另外,使用编辑器中的grep
或“在文件中查找”以确保该宏生效的每个地方都不会造成麻烦。
重要提示:在每个文件中,确保{/ 1}}文件包含 后可能使用.h
符号的任何标准标头。你不希望那个宏在那些......中生效......
注意:这是一个丑陋的黑客。然后,根据某些标准,几乎所有涉及C预处理器宏的内容都可以被视为丑陋的黑客;)。然后,让现有的不兼容代码库合作并协同工作通常是一种可以接受黑客攻击的情况,特别是如果长期维护不是问题。
注2:根据this answer和评论中的指出,这是C标准的未定义行为。请记住这一点,如果打算将软件维护更长时间,那么只需获得一次可运行的可执行二进制文件。但我添加了a better solution。
答案 1 :(得分:4)
请注意,如果在代码中实际使用了标准getline
的GCC标头,则可能会触发未定义的行为。这些是相关的信息来源(强调我的):
1.3.3保留名称
来自ISO C标准的所有库类型,宏,变量和函数的名称都是无条件保留的;您的程序可能不会重新定义这些名称。 如果您的程序明确包含定义或声明它们的头文件 ,则保留所有其他库名称。这些限制有几个原因:
[...]
和C99标准草案(N1256):
7.1.3保留标识符
1
每个标头声明或定义其相关子条款中列出的所有标识符,以及 可选地声明或定义其关联的未来库方向子条款和标识符中列出的标识符,这些标识符始终保留用于任何用途或用作文件范围标识符。
[...]
2
不保留其他标识符。如果程序在保留它的上下文中声明或定义标识符(除了7.1.4允许的标识符), 或将保留标识符定义为宏名称,则行为是未定义的。 强>
3
如果程序删除(使用#undef)第一个标识符的任何宏定义 上面列出的组,行为未定义。
因此,如果在代码中包含getline
标题,即使其他帖子中建议的宏技巧也会调用未定义的行为。
不幸的是,在这种情况下,唯一安全的选择是手动重命名所有getline
次调用。
答案 2 :(得分:2)
C需要唯一的函数名称。 但你可以使用-fno-builtin或-ffreestanding gcc标志。 请参阅gcc手册页中有关此标志的说明。
答案 3 :(得分:1)
一种常见的方法是使用形成某种命名空间的前缀。有时你可以看到用于此的宏来更容易地更改命名空间名称,例如。
#define MYAPP(f) myapp_##f
然后使用
int MYAPP(add)(int a, int b) {
return a + b;
}
这定义了一个函数myapp_add
,您也可以像
MYAPP(add)(3, 5);
答案 4 :(得分:1)
这个标准合规性问题开始让我感到烦恼,所以我做了一些实验。这是第二个答案,可能比我目前接受的答案更好。
首先,解决方案:
只需使用值_XOPEN_SOURCE
定义宏699
,方法是将其添加到编译器命令行选项
-D_XOPEN_SOURCE=699
究竟是什么,这取决于应用程序构建系统,但一种可能的工作方式是定义CFLAGS环境变量,并查看它是否在重建时生效:
export CFLAGS="-D_XOPEN_SOURCE=699"
其他替代方法是在应用程序的每个#define _XOPEN_SOURCE 699
文件中包含之前添加.c
,以防它使用某些深奥的构建系统并且您无法将其添加到编译选项中,但是它来自命令行是最好的。
然后解释一下:
Man page of getline指定getline
仅在某些标准下定义,例如_XOPEN_SOURCE>=700
。因此,通过在包含相关文件之前定义较小的值,我们排除了库声明。有关这些功能测试宏的更多信息,请参见in GNU libc manual。
我预计会有一些链接器问题,但没有,我的调查结果this question在这里。总而言之,链接器将首选来自链接目标文件的符号(至少使用 gcc ),并且只有在没有找到符号的情况下才会查看动态库。因此,由于getline
不是 ISO C符号,GNU libc文档quoted in this answer似乎暗示,使用此答案的_XOPEN_SOURCE
技巧后,可以在应用程序中使用它。仍然,要小心使用POSIX getline
的其他库并最终调用应用程序的函数(可能使用不同的参数,导致未定义的行为,可能是崩溃)。
答案 5 :(得分:-1)
这是解决您问题的简洁方法。诀窍是LD_PRELOAD。 我在我的一个问题帖子中做了类似的事情。参见以下内容。 Hack the standard function in library and call the native library function afterwards
您可以在单独的文件中定义getline()。这将使设计也变得干净。现在,编译该c文件;
$gcc -c -g -fPIC <file.c>
。
这将创建file.o.现在,制作它的共享对象。
-g用于调试。
-fPIC用于位置无关代码。这将有助于节省RAM SIZE。如果指定-fPIC选项,则将共享文本段。
$gcc -shared libfile.so file.o
现在,将您的主文件与此共享对象链接。
执行时,使用LD_PRELOAD,这将使用您的库而不是本机API。
$LD_PRELOAD=<path to libfile.so>/libfile.so ./main.out
如果您喜欢我的答案,那么请欣赏。我在上一篇文章Hack the standard function in library and call the native library function afterwards中做过类似的事情。