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
Post a Comment