Reputation: 3893
Consider the following code:
//#import <Foundation/Foundation.h>
int main(int argc, const char *argv[]) {
@autoreleasepool {
NSLog(@"Hello World!");
}
return 0;
}
I cannot understand why it could be built and run? w/out Foundation header!
For me it is still strange that C compiler COMPILES this code w/out header i.e. w/out DECLARATIONS. It's strange that compiler matches my function somehow to already compiled code (Foundation) and succeeds. Are there some links to C standard that will explain me how compiler resolves token that recognized as a function and was never previously declared?
Please, explain!!
UPDATE: These if not due to pre-compiled headers
Thank you! But NO. I tested it the following way - just typed Hello World code in vi editor and saved it as main.m file. Than compiled it with clang from Terminal. And e-thing went Okay with 1 warning only:
main.m:8:9: warning: implicitly declaring library function 'NSLog' with type 'void (id, ...)' NSLog(@"Hello World!");
^ main.m:8:9: note: please include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLog'
1 warning generated.
UPDATE: Just attaching all the images step-by-step:
Upvotes: 3
Views: 3648
Reputation: 93
Header files normally serve the purpose of instructing a compiler what to expect out of a function prototype. That being said, if the header file is not included ( which means in the absence of a function prototype), modern compilers like gcc and clang in this case try to 'infer' the prototype of a function when they are used in the code.
In this case, when the NSLog() function is called, the compiler tries to infer it's prototype and that's precisely the warning being issued. Additionally, these header files have no significance during link time; All the linker needs to know is 1) do i have function ( main() ) to enter and run the executable and 2) do i have the corresponding library / object code for all the symbols being used ( ofcourse am simplifying a bit here). So as long as the foundation library is made available to the linker (-fobjc-arc ) linking should go through fine.
As folks have already mentioned, not including header files is a bad practice. Because it helps compilers to catch issues up front and ensure the functions are called with appropriate data.
Upvotes: 1
Reputation: 400274
This doesn't appear to be documented anywhere that I can find, but clearly the -fobjc-arc
command line flag is causing the linker to automatically link in Foundation.framework.
Without -fobjc-arc
:
$ clang main.m
main.m:3:5: warning: implicitly declaring library function 'NSLog' with type
'void (id, ...)'
NSLog(@"Hello World!");
^
main.m:3:5: note: please include the header <Foundation/NSObjCRuntime.h> or
explicitly provide a declaration for 'NSLog'
1 warning generated.
Undefined symbols for architecture x86_64:
"_NSLog", referenced from:
_main in main-db9728.o
"___CFConstantStringClassReference", referenced from:
CFString in main-db9728.o
"_objc_autoreleasePoolPop", referenced from:
_main in main-db9728.o
"_objc_autoreleasePoolPush", referenced from:
_main in main-db9728.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
With -fobjc-arc
:
$ clang main.m -fobjc-arc
main.m:3:5: warning: implicitly declaring library function 'NSLog' with type
'void (id, ...)'
NSLog(@"Hello World!");
^
main.m:3:5: note: please include the header <Foundation/NSObjCRuntime.h> or
explicitly provide a declaration for 'NSLog'
1 warning generated.
Carol Norum explained why it compiles fine without including the proper header file. Nevertheless, this is bad practice, and you should always include the proper header files you need and explicitly link against the frameworks you need. It may work this time, but it may hide some insidious bugs and fail in spectacular ways with other code.
Upvotes: 0
Reputation: 224904
There's no reason it shouldn't compile. As you're seeing, without that header present, the compiler is assuming NSLog
is a function with signature void NSLog(id, ...)
. In this case, you're even luckier, because that signature happens to be compatible with the real function declaration - meaning your program will actually even work correctly as well:
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
Note that without linking against Foundation, the build won't succeed:
$ make example
cc example.m -o example
example.m:3:9: warning: implicitly declaring library function 'NSLog' with type
'void (id, ...)'
NSLog(@"Hello World!");
^
example.m:3:9: note: please include the header <Foundation/NSObjCRuntime.h> or
explicitly provide a declaration for 'NSLog'
1 warning generated.
Undefined symbols for architecture x86_64:
"_NSLog", referenced from:
_main in example-943cd4.o
"___CFConstantStringClassReference", referenced from:
CFString in example-943cd4.o
"_objc_autoreleasePoolPop", referenced from:
_main in example-943cd4.o
"_objc_autoreleasePoolPush", referenced from:
_main in example-943cd4.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [example] Error 1
You need to add -framework Foundation
:
$ CFLAGS="-framework Foundation" make example
cc -framework Foundation example.m -o example
example.m:3:9: warning: implicitly declaring library function 'NSLog' with type
'void (id, ...)'
NSLog(@"Hello World!");
^
example.m:3:9: note: please include the header <Foundation/NSObjCRuntime.h> or
explicitly provide a declaration for 'NSLog'
1 warning generated.
Upvotes: 10
Reputation: 1552
The foundation framework is probably imported in your precompiled header (.pch)
Upvotes: 2