nickolay
nickolay

Reputation: 3893

Objective-C: "Hello world" COMPILED! without Foundation header. Why?

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: The only file in directory main.m Contents of main.m - VIM Compiling ... Compiled! Test run of the application built

Upvotes: 3

Views: 3648

Answers (4)

user3012653
user3012653

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

Adam Rosenfield
Adam Rosenfield

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

Carl Norum
Carl Norum

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

lucianomarisi
lucianomarisi

Reputation: 1552

The foundation framework is probably imported in your precompiled header (.pch)

Upvotes: 2

Related Questions