如何在stdio.h(CLANG,OSX)中实现getline函数的自定义版本(回答:更改用于编译的POSIX标准)

如何在stdio.h(CLANG,OSX)中实现getline函数的自定义版本(回答:更改用于编译的POSIX标准),c,clang,posix,getline,stdio,C,Clang,Posix,Getline,Stdio,晚上好, 我正在练习Kernighan和Ritchie的经典“C编程语言” 在一些地方,练习让您创建自己版本的函数,该函数与标准库中的函数名重复。我不想为我的版本创建一个替代名称,而是想告诉编译器,我更愿意使用我的函数版本,而不是标准库函数 具体来说,如果我试图编译练习1-18的解决方案,从每行输入中删除尾随空格和制表符,我将使用函数“getline”从stdin中读取该行。不幸的是,这会生成一个编译器错误,因为getline是在stdio.h中定义的 我尝试过使用#undef,但似乎无法实现

晚上好,

我正在练习Kernighan和Ritchie的经典“C编程语言”

在一些地方,练习让您创建自己版本的函数,该函数与标准库中的函数名重复。我不想为我的版本创建一个替代名称,而是想告诉编译器,我更愿意使用我的函数版本,而不是标准库函数

具体来说,如果我试图编译练习1-18的解决方案,从每行输入中删除尾随空格和制表符,我将使用函数“getline”从stdin中读取该行。不幸的是,这会生成一个编译器错误,因为getline是在stdio.h中定义的

我尝试过使用#undef,但似乎无法实现

我搜索了之前的其他类似问题,发现了[这一个][1];然而,它似乎需要对标准库头进行黑客攻击,我不希望这样做

提前谢谢你的帮助

以下是代码(删除我的简短评论):

更新1

从定义中删除“static”后,错误更改为:

cc -std=c99 -Wall -g -I. -c -o obj/cleantrailsnblanks.o cleantrailsnblanks.c
cleantrailsnblanks.c:14:8: error: conflicting types for 'getline'
size_t getline(char s[], size_t lim) {
       ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/stdio.h:442:9: note: previous declaration is here
ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
        ^
cleantrailsnblanks.c:35:40: error: too few arguments to function call, expected 3, have 2
while ((len = getline(line, MAXLINE)) > 0)
              ~~~~~~~              ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/stdio.h:442:1: note: 'getline' declared here
ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
^
2 errors generated.
make: *** [obj/cleantrailsnblanks.o] Error 1
回答

请参阅本讨论:

解决方案是在包含stdio.h之前添加这两行:

#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#未定义(POSIX)C(源代码)
#定义\u POSIX\u C\u源200112L
#包括

这设置了使用POSIX.1-2001标准编译代码的方法,而不是将GNU getline()扩展添加到标准中的POSIX.1-2008标准。

这取决于您将如何使用它

如果它只在一个.c文件中,我会将您的方法名称更改为其他名称,然后将所有调用更改为新名称,或者在文件顶部添加一个
#define realName overrideName


如果这是更通用的,或者对于单元测试中的模拟,我会将您重写的
getline
方法放入它自己的.c文件中。将其编译为.so,然后在启动应用程序时,在任何其他库之前告诉您的系统您的覆盖.so文件。

我认为您的练习是想让您了解动态注入共享库

gcc-shared-o libname.so filename.c那样编译您的文件(不带
static

在OS X上,您需要设置3个环境变量:

  • setenv DYLD\u库路径。

  • setenv DYLD\u INSERT\u libname.so

  • setenv DYLD\u FORCE\u FLAT\u命名空间1

其他一些信息:

编辑

让我通过更改
id

$> id
uid=501(yourname) gid(staff) groups ...
创建一个文件
getuid.c

int getuid() {
     return (0);
}

int geteuid() {
     return (0);
}
使用
gcc-shared-o myuid.so getuid.c编译

int getuid() {
     return (0);
}

int geteuid() {
     return (0);
}
您可以编写
nmmyuid.so
并查看其中的函数

然后设置环境变量

setenv DYLD_LIBRARY_PATH .
setenv DYLD_INSERT_LIBRARIES libname.so
setenv DYLD_FORCE_FLAT_NAMESPACE 1
它可以与导出一起使用,具体取决于您的shell

然后
id
结果如下所示:

$> id
uid=0(yourname) gid(staff) groups ...
K&R现在是一本(非常)古老的书,你需要考虑到这一点。声明/定义
getline
,与手册所述完全一致(实际上)。当您在OSX上时,手册上说:

概要

 #include <stdio.h>

 ssize_t
 getline(char ** restrict linep, size_t * restrict linecapp, FILE * restrict stream);
#包括
ssize\u t
getline(字符**限制行,大小*限制行,文件*限制流);
使用那个原型


如果您确实希望使用原始原型,也可以稍微更改练习,并将函数重命名为
mygetline

请参考以下两个讨论(第二个是最相关的):

解决方案是在包含stdio.h之前添加这两行:

#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#未定义(POSIX)C(源代码)
#定义\u POSIX\u C\u源200112L
#包括

这将设置使用POSIX.1-2001标准编译代码,而不是POSIX.1-2008标准,在POSIX.1-2008标准中,GNU getline()扩展被添加到标准中。

删除
静态
限定符。确保函数的声明与标准函数相同。因此,请摆脱
static
。我已经尝试过了,因为这是错误消息提供的指导,但仍然不起作用。我将用结果更新我的问题。另外,我的声明将与标准函数不同,因为getline的K&R示例与标准函数不同。这是我需要重写而不考虑标准函数定义的原因之一。阅读所有答案。