4

我正在编译一个名为 nauty 的程序。该程序使用规范的函数名称 getline,它也是标准 GNU C 库的一部分。

是否可以在编译时告诉 GCC 使用这个程序定义的函数?

4

6 回答 6

6

一种解决方案:

现在您在某个应用程序.h文件中声明了函数,例如:

int getline(...); // the custon getline

将其更改为:

int application_getline(...); // the custon getline
#define getline application_getline

我认为应该这样做。它还将修复.c定义函数的文件,假设它包含该.h文件。

另外,使用grep编辑器或“在文件中查找”确保该宏生效的每个地方都不会造成麻烦。

重要提示:在每个文件中,确保该.h文件包含任何可能使用getline符号的标准头之后。您不希望该宏在那些...中生效

注意:这是一个丑陋的黑客。话又说回来,几乎所有涉及 C 预处理器宏的东西都可以被认为是丑陋的 hack,按照某些标准;)。再说一次,让现有的不兼容的代码库进行合作和协同工作通常是可以接受黑客攻击的情况,尤其是在不考虑长期维护的情况下。

注意2:根据此答案并在评论中指出,这是 C 标准未定义的行为。请记住这一点,如果打算将软件维护更长的时间,那么只需获得一个可以工作的可执行二进制文件。但我添加了一个更好的解决方案

于 2013-09-25T09:29:21.990 回答
4

请注意,如果getline您的代码中实际使用了定义标准的 GCC 标头,则您可能会触发未定义的行为。这些是相关的信息来源(重点是我的):

libc手册:

1.3.3 保留名称

无条件保留所有来自 ISO C 标准的库类型、宏、变量和函数的名称;您的程序可能不会重新定义这些名称。如果您的程序显式包含定义或声明它们的头文件,则保留所有其他库名称。这些限制有几个原因:

[...]

和 C99 标准草案(N1256):

7.1.3 保留标识符

1

每个标头声明或定义其相关子条款中列出的所有标识符,并可选地声明或定义其相关的未来库方向子条款中列出的标识符和始终保留用于任何用途或用作文件范围标识符的标识符。

[...]

2

没有保留其他标识符。如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的除外),或将保留标识符定义为宏名称,则行为未定义。

3

如果程序删除(使用#undef)上面列出的第一组标识符的任何宏定义,则行为未定义。

因此,如果您在代码中包含标题,即使是另一篇文章中建议的宏技巧也会调用未定义的行为getline

不幸的是,在这种情况下,唯一安全的选择是手动重命名所有getline调用。

于 2013-09-25T10:18:23.090 回答
2

C 需要唯一的函数名称。但您可以使用 -fno-builtin 或 -ffreestanding gcc 标志。请参阅 gcc 手册页中有关此标志的描述。

于 2013-09-25T10:17:52.890 回答
1

一种常见的方法是使用形成某种命名空间的前缀。有时您可以看到用于此的宏以使更改命名空间名称更容易,例如

#define MYAPP(f) myapp_##f

然后像这样使用

int MYAPP(add)(int a, int b) {
    return a + b;
}

这定义了一个函数myapp_add,您也可以调用它

MYAPP(add)(3, 5);
于 2013-09-25T09:22:54.313 回答
1

这个标准合规问题开始困扰我,所以我做了一些实验。这是第二个答案,可能比我目前接受的答案更好。

首先,解决方案

只需通过将其添加到编译器命令行选项来定义_XOPEN_SOURCE带有值的宏699

-D_XOPEN_SOURCE=699

具体如何,这取决于应用程序构建系统,但一种可能的工作方式是定义 CFLAGS 环境变量,并查看它在重建时是否生效:

export CFLAGS="-D_XOPEN_SOURCE=699"

其他替代方法是在应用程序的每个文件中添加#define _XOPEN_SOURCE 699之前包含的内容.c,以防它使用一些深奥的构建系统并且您无法将其添加到编译选项中,但从命令行执行此操作是更可取的。

然后是一些解释

getline 的手册页指定,getline仅在某些标准下定义,例如 if _XOPEN_SOURCE>=700。因此,通过在包含相关文件之前定义一个较小的值,我们排除了库声明。有关这些功能测试宏的更多信息,请参见GNU libc 手册

我预计也会有一些链接器问题,但没有,我的调查在这里产生了这个问题。总而言之,链接器将更喜欢链接目标文件中的符号(至少使用gcc),并且仅在没有找到符号时才查看动​​态库。因此,由于getline不是ISO C 符号,因此此答案中引用的 GNU libc 文档似乎暗示在使用_XOPEN_SOURCE此答案的技巧后,可以在应用程序中使用它。不过,请注意使用 POSIXgetline并最终调用应用程序函数的其他库(可能使用不同的参数,导致未定义的行为,可能是崩溃)。

于 2013-09-26T07:04:35.580 回答
-1

这是解决您问题的巧妙方法。诀窍是 LD_PRELOAD。我在我的一个问题帖子中做了类似的事情。请参阅以下内容。 破解库中的标准函数,然后调用本机库函数

您可以在单独的文件中定义 getline()。这也将使设计干净。现在,编译那个c文件; $gcc -c -g -fPIC <file.c>. 这将创建 file.o。现在,制作它的共享对象。-g 用于调试。-fPIC 用于与位置无关的代码。这将有助于节省 RAM SIZE。如果您指定 -fPIC 选项,则将共享文本段。

$gcc -shared libfile.so file.o

现在,将您的主文件与此共享对象链接。

gcc -g main.c -o main.out -lfile

执行时,使用 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 after my previous post Hack the standard function in library and call the native library function after .

于 2013-09-25T11:11:20.257 回答