Objective-C:“Hello world”编译完成!没有Foundation标题。为什么?

时间:2014-06-13 15:35:12

标签: objective-c c compilation

请考虑以下代码:

//#import <Foundation/Foundation.h>

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSLog(@"Hello World!");
    }
    return 0;
}

我无法理解为什么它可以构建和运行? w / out Foundation标题!

对于我来说,C编译器编译此代码w / out标题即w / out DECLARATIONS仍然很奇怪。奇怪的是,编译器以某种方式将我的函数与已编译的代码(Foundation)匹配并成功。是否有一些指向C标准的链接,它将向我解释编译器如何解析被识别为函数且以前从未声明过的令牌?

请解释!!

更新:如果不是由于预编译的标题

谢谢!但不是。我通过以下方式测试它 - 只需在vi编辑器中键入Hello World代码并将其保存为main.m文件。比用Terminal的clang编译它。电子邮件只有1个警告就可以了:

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.

更新:只需逐步附加所有图片: The only file in directory main.m Contents of main.m - VIM Compiling ... Compiled! Test run of the application built

4 个答案:

答案 0 :(得分:6)

没有理由不编译。正如您所看到的,如果没有该标头,编译器会假设NSLog是一个带有签名void NSLog(id, ...)的函数。在这种情况下,您甚至更幸运,因为该签名恰好与实际功能声明兼容 - 这意味着您的程序实际上甚至可以正常工作

FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);

请注意,如果没有链接与Foundation,则构建将不会成功:

$ 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

您需要添加-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.

答案 1 :(得分:2)

基础框架可能已导入预编译头文件(.pch)

答案 2 :(得分:1)

头文件通常用于指示编译器从函数原型中得到什么。话虽这么说,如果没有包含头文件(这意味着没有函数原型),在这种情况下,像gcc和clang这样的现代编译器会在代码中使用时尝试“推断”函数的原型。

在这种情况下,当调用NSLog()函数时,编译器会尝试推断它的原型,这正是发出的警告。另外,这些头文件在链接时没有意义;所有链接器需要知道的是1)我是否有函数(main())来输入和运行可执行文件; 2)我是否有相应的库/目标代码用于所有使用的符号(当然这里简化了一点) 。因此,只要基础库可供链接器使用(-fobjc-arc),链接应该可以正常进行。

正如人们已经提到的,不包括头文件是一种不好的做法。因为它有助于编译器预先发现问题并确保使用适当的数据调用函数。

答案 3 :(得分:0)

这似乎没有记录在我能找到的任何地方,但显然-fobjc-arc命令行标志导致链接器在Foundation.framework中自动链接。

没有-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)

使用-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为什么编译正常而不包含正确的头文件。然而,这是不好的做法,您应该始终包含所需的正确头文件,并明确链接到您需要的框架。它可能这个时间,但它可能隐藏一些阴险的错误,并以其他代码的壮观方式失败。