在程序violates内调用{+ 1}} C ++标准
main
在lecture Chandler Carruth,大约! 22.40'说
如果您已编写过编译器测试,则表示您已拨打
的电话void f() { main(); // an endless loop calling main ? No that's not allowed } int main() { static int = 0; std::cout << i++ << std::endl; f(); }
这是如何相关的,或者标准不允许的事实是如何克服的?
答案 0 :(得分:4)
这里的要点是,如果您编写编译器测试代码,您可能希望使用一些不同的参数集测试调用main
并且可以执行此操作,并了解编译器将要测试。
标准禁止调用main
,以便main
可以拥有神奇的代码(例如构建全局对象或初始化某些数据结构的代码,将全局未初始化的POD数据清零等等)。但是,如果您正在为编译器编写测试代码,您可能会了解编译器是否执行此操作 - 如果是这样,在此步骤中实际执行的操作是什么,并在测试中考虑到这一点 - 例如,您可以“脏”一些全局变量,然后再次调用main并看到此变量确实再次设置为零。或者可能是main
在这个特定的编译器中确实不可调用。
由于Chandler正在谈论LLVM(以及C语言,Clang),他知道该编译器如何为main
生成代码。
这显然不适用于编译器的“黑盒测试”。在这样的测试套件中,您不能依赖编译器特别做任何事情,或者不做一些会损害您测试的事情。
与所有未定义的行为一样,它不能保证以任何特定的方式工作,但有时候,如果你知道编译器的实际实现,就有可能利用这种行为 - 只是不要认为它是好的编程,并且不要指望它以便携方式工作。
例如,在PC上,您可以通过以下方式写入文本屏幕(至少在配置MMU之前):
char *ptr = (char *)0xA0000;
ptr[0] = 'a';
ptr[1] = 7; // Determines the colour.
根据标准,这是未定义的行为,因为标准确实表示您只能使用指向C或C ++运行时内部分配的指针。但很明显,你无法在显卡中分配内存......从技术上讲,它是UB,但是猜想Linux和Windows在早期启动时会做什么?直接写入VGA内存... [或者至少他们曾经使用过一段时间,当我上次看到它时]。如果您知道您的硬件,这应该适用于我所知道的每个编译器 - 如果不知道,您可能无法使用它来编写低级驱动程序代码。但标准尚未定义,“UB消毒剂”可能会对代码抱有呻吟。