c - How are library functions are linked in this case? -


i come across code , blog says works fine on 32 bit architecture. didn't test it; however, have doubt linkage of libraries in case. how compiler link string library main since not aware library link?

so if include <string.h> should work fine; however, if don't include <string.h> then, per blog, runs in 32 bit architecture , fails run on 64 bit architecture.

#include <errno.h> #include <stdio.h>  int main(int argc, char *argv[]) {     file *fp;      fp = fopen(argv[1], "r");     if (fp == null) {         fprintf(stderr, "%s\n", strerror(errno));         return errno;     }      printf("file exist\n");      fclose(fp);      return 0; } 

the code shown compile if allow compiler infer functions not declared return int. valid in c89/c90 marked obsolescent; c99 , c11 require functions declared before used. gcc prior version 5.1.0 assumes c90 mode default; had turn 'reject code' warnings on. gcc 5.1.0 , onwards assumes c11 default. @ least warnings code without compilation options turn them on.

the code link fine because function name strerror() regardless of whether declared or not, , linker can find function in standard c library. in general, functions in standard c library automatically made available linking — and, indeed, there lot of not standard functions available. c not have type-safe linkage c++ (but c++ insists on having every function declared before used, code not compile c++ without header.)

for historical reasons, maths library separate , needed specify -lm in order link it. in large part because hardware floating point not universal, machines needed library using hardware, , other machines needed software emulation of floating point arithmetic. platforms (linux, example) still require separate -lm option if use functions declared in <math.h> (and <tgmath.h>); other platforms (mac os x, example) not — there -lm satisfy build systems link it, maths functions in main c library.

if code compiled on standard 32-bit platform ilp32 (int, long, pointer 32-bit), many architectures, assuming strerror() returns int assumes returns same amount of data if returns char * (which strerror() returns). so, when code pushes return value strerror() onto stack fprintf(), correct amount of data pushed.

note architectures (notably motorola m680x0 series) return addresses in address register (a0) , numbers in general register (d0), there problems on machines 32-bit compilation: compiler try returned value data register instead of address register, , not set strerror() — leading chaos.

with 64-bit architecture (lp64), assuming strerror() returns 32-bit int means compiler collect 32-bits of 64-bit address returned strerror() , push on stack fprintf() work with. when tried treat truncated address valid, things go awry, leading crash.

when missing <string.h> header added, compiler knows strerror() function returns char * , happiness , delight once more, when file program told doesn't exist.

if wise, ensure compiler compiling in fussy mode, rejecting plausibly erroneous. when use default compilation on code, get:

$ gcc -std=c11 -o3 -g -wall -wextra -werror -wmissing-prototypes \ >      -wstrict-prototypes -wold-style-definition bogus.c -o bogus bogus.c: in function ‘main’: bogus.c:10:33: error: implicit declaration of function ‘strerror’ [-werror=implicit-function-declaration]          fprintf(stderr, "%s\n", strerror(errno));                                  ^ bogus.c:10:25: error: format ‘%s’ expects argument of type ‘char *’, argument 3 has type ‘int’ [-werror=format=]          fprintf(stderr, "%s\n", strerror(errno));                          ^ bogus.c:10:25: error: format ‘%s’ expects argument of type ‘char *’, argument 3 has type ‘int’ [-werror=format=] bogus.c:4:14: error: unused parameter ‘argc’ [-werror=unused-parameter]  int main(int argc, char *argv[])               ^ cc1: warnings being treated errors $ 

the 'unused argument' error reminds you should checking there argument pass fopen() before try open file.

fixed code:

#include <string.h> #include <errno.h> #include <stdio.h>  int main(int argc, char *argv[]) {     file *fp;      if (argc != 2)     {         fprintf(stderr, "usage: %s file\n", argv[0]);         return 1;     }      fp = fopen(argv[1], "r");     if (fp == null)     {         fprintf(stderr, "%s: file %s not opened reading: %s\n",                 argv[0], argv[1], strerror(errno));         return errno;     }      printf("file %s exists\n", argv[1]);      fclose(fp);      return 0; } 

build:

$ gcc -std=c11 -o3 -g -wall -wextra -werror -wmissing-prototypes \ >     -wstrict-prototypes -wold-style-definition bogus.c -o bogus   $ 

run:

$ ./bogus bogus file bogus exists $ ./bogus bogus2 ./bogus: file bogus2 not opened reading: no such file or directory $ ./bogus usage: ./bogus file $ 

note error messages include program name , report standard error. when file known, error message includes file name; easier debug error if program in shell script if message just:

no such file or directory 

with no indication of program or file encountered problem.

when remove #include <string.h> line fixed code shown, can compile , run this:

$ gcc -o bogus90 bogus.c bogus.c: in function ‘main’: bogus.c:18:35: warning: implicit declaration of function ‘strerror’ [-wimplicit-function-declaration]                  argv[0], argv[1], strerror(errno));                                    ^ $ gcc -std=c90 -o bogus90 bogus.c $ ./bogus90 bogus11 segmentation fault: 11 $ 

this tested gcc 5.1.0 on mac os x 10.10.5 — is, of course, 64-bit platform.


Comments