How to implement custom versions of the getline function in stdio.h (CLANG, OS X) (ANSWER: change the POSIX standard used for compilation)

Good evening,

I am working on exercises in Kernigan and the Ritchie classic "C Programming Language."

In several places in the exercise, you created your own version of a function that duplicates the function name in the standard library. Instead of creating an alternate name for my version, I would really like to tell the compiler that I would rather use my version of the function and then the standard library function.

To get specific, if I try to compile a solution for implementation 1-18 that removes trailing spaces and tabs from each input line, I use the 'getline' function to read in a line from stdin. Unfortunately, this generates a compiler error, as getline is defined in stdio.h.

I tried using #undef but could not get this to work.

I searched for other previous similar questions and found [this] [1]; however, it seems like you need to crack the standard library header, which I would rather not do.

Thank you for your help.

Here is the code (devoid of my comments for brevity):

#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] = '\0';

    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);
}

And, I get a message:

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

UPDATE 1

After I reset the “static” from my definition, the error changed to:

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

ANSWER

: getline " 1 K & R2?

, stdio.h:

#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>

POSIX.1-2001 POSIX.1-2008, GNU getline() .

+4
4

( - ):

, stdio.h:

#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>

POSIX.1-2001 POSIX.1-2008, GNU getline() .

0

, , .

( static), gcc -shared -o libname.so filename.c

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, .

id :

$> id
uid=0(yourname) gid(staff) groups ...
0

K & R () , . / getline , (). OSX, :

 #include <stdio.h>

 ssize_t
 getline(char ** restrict linep, size_t * restrict linecapp, FILE * restrict stream);

, .

mygetline, .

0

, .

If it is in only one .c file, I would change the method name to another, then either change all the calls to your new name, or add #define realName overrideNameto the top of your file.

If this is more general or for mockery in unit testing, I would take your overridden method getlineinto my own .c file. Compiler it to .so then tell your system about your redefinition of the .so file before any other libraries when you start the application.

-1
source

All Articles