如何在 stdio.h (CLANG, OS X) 中实现自定义版本的 getline 函数(答案:更改用于编译的 POSIX 标准)
How to implement custom versions of the getline function in stdio.h (CLANG, OS X) (ANSWER: Change POSIX standard used to compile)
晚上好,
我正在完成 Kernighan 和 Ritchie 的经典作品 "The C Programming Language" 中的练习。
练习中有几个地方要求您创建自己的函数版本,该函数的名称与标准库中的函数名称相同。我不想为我的版本创建一个替代名称,我真的很想告诉编译器我宁愿使用我的函数版本而不是标准库函数。
具体来说,如果我尝试编译练习 1-18 的解决方案,该解决方案从每行输入中删除尾随空白和制表符,我将使用函数 'getline' 从标准输入中读取该行。不幸的是,这会产生编译器错误,因为 getline 是在 stdio.h.
中定义的
我试过使用#undef,但似乎无法正常工作。
我已经搜索过其他类似的问题并找到了[这个][1];然而,它似乎需要破解标准库头文件,而我不想这样做。
提前感谢您的帮助。
这是代码(为简短起见去掉了我的注释):
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1000
static size_t getline(char s[], size_t lim) {
char c;
size_t i = 0;
while (--lim > 0 && (c = (char)getchar()) != (char)EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '[=12=]';
return i;
}
int main(void) {
char line[MAXLINE] = "";
size_t len = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > MAXLINE)
printf("%s", line);
exit(EXIT_SUCCESS);
}
而且,我得到的错误是:
cc -std=c99 -Wall -g -I. -c -o obj/cleantrailsnblanks.o cleantrailsnblanks.c
cleantrailsnblanks.c:14:15: error: static declaration of 'getline' follows non-static declaration
static 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
更新 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
回答
参考这个讨论:Why do I get a "conflicting types for getline" error when compiling the longest line example in chapter 1 of K&R2?
解决方案是在包含 stdio.h:
之前添加这两行
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
这设置使用 POSIX.1-2001 标准编译代码,而不是 POSIX.1-2008 标准,其中 GNU getline() 扩展被添加到标准.
这取决于您将如何使用它。
如果它只在一个 .c 文件中,我会将您的方法名称更改为其他名称,然后将所有调用更改为您的新名称或在文件顶部添加 #define realName overrideName
。
如果这更通用,或者为了在单元测试中进行模拟,我会将您重写的 getline
方法放入其自己的 .c 文件中。将其编译为 .so,然后在启动您的应用程序时,在任何其他库之前告诉您的系统您的覆盖 .so 文件。
我认为你的练习想让你学习动态注入和共享库。
像gcc -shared -o libname.so filename.c
一样编译你的文件(没有static
)
在 OS X 上你需要设置 3 个环境变量 :
setenv DYLD_LIBRARY_PATH .
setenv DYLD_INSERT_LIBRARIES libname.so
setenv DYLD_FORCE_FLAT_NAMESPACE 1
其他一些信息:http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
编辑
让我通过更改 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
编译
可以写nm myuid.so
,看看里面的函数
然后设置你的环境变量
setenv DYLD_LIBRARY_PATH .
setenv DYLD_INSERT_LIBRARIES libname.so
setenv DYLD_FORCE_FLAT_NAMESPACE 1
它可能与 export
一起使用,取决于您的 shell。
然后 id
结果如下:
$> id
uid=0(yourname) gid(staff) groups ...
K&R 现在是一本(非常)旧的书,您需要考虑到这一点。 Declare/define getline
完全按照手册所说(实际上)。正如你在 OSX,手册上说:
SYNOPSIS
#include <stdio.h>
ssize_t
getline(char ** restrict linep, size_t * restrict linecapp, FILE * restrict stream);
使用那个原型。
如果你真的想使用原始原型,你也可以稍微改变一下练习并将函数重命名为mygetline
。
参考这两个讨论(第二个最相关):
- Why do I get a "conflicting types for getline" error when compiling the longest line example in chapter 1 of K&R2?
- Can an ANSI C-compliant implementation include additional functions in its standard library?
解决方案是在包含 stdio.h:
之前添加这两行
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
这设置使用 POSIX.1-2001 标准编译代码,而不是 POSIX.1-2008 标准,其中 GNU getline() 扩展被添加到标准.
晚上好,
我正在完成 Kernighan 和 Ritchie 的经典作品 "The C Programming Language" 中的练习。
练习中有几个地方要求您创建自己的函数版本,该函数的名称与标准库中的函数名称相同。我不想为我的版本创建一个替代名称,我真的很想告诉编译器我宁愿使用我的函数版本而不是标准库函数。
具体来说,如果我尝试编译练习 1-18 的解决方案,该解决方案从每行输入中删除尾随空白和制表符,我将使用函数 'getline' 从标准输入中读取该行。不幸的是,这会产生编译器错误,因为 getline 是在 stdio.h.
中定义的我试过使用#undef,但似乎无法正常工作。
我已经搜索过其他类似的问题并找到了[这个][1];然而,它似乎需要破解标准库头文件,而我不想这样做。
提前感谢您的帮助。
这是代码(为简短起见去掉了我的注释):
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1000
static size_t getline(char s[], size_t lim) {
char c;
size_t i = 0;
while (--lim > 0 && (c = (char)getchar()) != (char)EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '[=12=]';
return i;
}
int main(void) {
char line[MAXLINE] = "";
size_t len = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > MAXLINE)
printf("%s", line);
exit(EXIT_SUCCESS);
}
而且,我得到的错误是:
cc -std=c99 -Wall -g -I. -c -o obj/cleantrailsnblanks.o cleantrailsnblanks.c
cleantrailsnblanks.c:14:15: error: static declaration of 'getline' follows non-static declaration
static 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
更新 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
回答
参考这个讨论:Why do I get a "conflicting types for getline" error when compiling the longest line example in chapter 1 of K&R2?
解决方案是在包含 stdio.h:
之前添加这两行#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
这设置使用 POSIX.1-2001 标准编译代码,而不是 POSIX.1-2008 标准,其中 GNU getline() 扩展被添加到标准.
这取决于您将如何使用它。
如果它只在一个 .c 文件中,我会将您的方法名称更改为其他名称,然后将所有调用更改为您的新名称或在文件顶部添加 #define realName overrideName
。
如果这更通用,或者为了在单元测试中进行模拟,我会将您重写的 getline
方法放入其自己的 .c 文件中。将其编译为 .so,然后在启动您的应用程序时,在任何其他库之前告诉您的系统您的覆盖 .so 文件。
我认为你的练习想让你学习动态注入和共享库。
像gcc -shared -o libname.so filename.c
static
)
在 OS X 上你需要设置 3 个环境变量 :
setenv DYLD_LIBRARY_PATH .
setenv DYLD_INSERT_LIBRARIES libname.so
setenv DYLD_FORCE_FLAT_NAMESPACE 1
其他一些信息:http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
编辑
让我通过更改 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
可以写nm myuid.so
,看看里面的函数
然后设置你的环境变量
setenv DYLD_LIBRARY_PATH .
setenv DYLD_INSERT_LIBRARIES libname.so
setenv DYLD_FORCE_FLAT_NAMESPACE 1
它可能与 export
一起使用,取决于您的 shell。
然后 id
结果如下:
$> id
uid=0(yourname) gid(staff) groups ...
K&R 现在是一本(非常)旧的书,您需要考虑到这一点。 Declare/define getline
完全按照手册所说(实际上)。正如你在 OSX,手册上说:
SYNOPSIS
#include <stdio.h> ssize_t getline(char ** restrict linep, size_t * restrict linecapp, FILE * restrict stream);
使用那个原型。
如果你真的想使用原始原型,你也可以稍微改变一下练习并将函数重命名为mygetline
。
参考这两个讨论(第二个最相关):
- Why do I get a "conflicting types for getline" error when compiling the longest line example in chapter 1 of K&R2?
- Can an ANSI C-compliant implementation include additional functions in its standard library?
解决方案是在包含 stdio.h:
之前添加这两行#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
这设置使用 POSIX.1-2001 标准编译代码,而不是 POSIX.1-2008 标准,其中 GNU getline() 扩展被添加到标准.