Clang和GCC在定义之前进行函数调用的不同诊断行为?

时间:2015-11-10 12:03:01

标签: c++ gcc arduino clang

让我们分析下面的代码示例:

int main() {
    return func();
}

int func() {
    return 1;
}

Clang将报告错误:

  

/private/tmp/src.cpp:2,9 - 错误 - 使用未声明的标识符'func'

但我可以在广泛使用的例子中找到很多这样的错误,例如:一些arduino来源: https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino

line 235 : disableI2CPins(); // invocation (before definition, no declaration before)

...

line 651 : void disableI2CPins() { .. } // definition

虽然在定义之前使用了函数,但是可以使用GCC成功编译代码。怎么会这样? Clang和GCC的行为有何不同? Clang是否有任何标志允许这样做?

PS。这是成功的命令行来编译Arduino IDE使用的代码:

  

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++   -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu = atmega2560 -DF_CPU = 16000000L -DARDUINO = 10600 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I / Applications / Arduino 。应用程序/内容/资源/的Java /硬件/ Arduino的/ AVR /核心/ Arduino的   -I /应用/ Arduino.app /内容/资源/的Java /硬件/ Arduino的/ AVR /变形/百万   -I /应用/ Arduino.app /内容/资源/的Java /库/伺服/ src目录   -I /应用/ Arduino.app /内容/资源/的Java /硬件/ Arduino的/ AVR /库/线   -I /应用/ Arduino.app /内容/资源/的Java /库/ Firmata / src目录   /var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp   -o /var/folders/64/fwfkm1k51zbd4_c5lwpsbljh0000gn/T/build8049651108713091801.tmp/StandardFirmata.cpp.o

3 个答案:

答案 0 :(得分:4)

这实际上与编译器无关,而是与Arduino IDE有关。 IDE有一个预处理步骤,它向前声明所有已定义的函数,这样您就不必担心文件中的函数放置。

我的强烈建议是遵循语言规则并向前声明您的功能或在使用之前定义它们。您的代码将更易于移植并且易于理解。

答案 1 :(得分:1)

不,您不希望clang在这方面表现得像gcc。事实上,使用-Wall-W(或-Wextra)可以让gccclang两者同时为您提供更多警告。

  

但我可以在广泛使用的例子中找到很多这样的错误

可悲的是,让CC++变得如此困难以至于广泛使用的示例还不够好。

Your example包含一个可能对该程序没有实际影响的错误。编辑:似乎IDE足够聪明,可以解决语言功能。有关详细信息,请参阅@ TartanLlama的答案。也许作者可以声称它是设计的。但clang感谢你将自己从自己身上拯救出来的情况很少。

C89§3.3.2.2,“函数调用”包括:

  

如果表达式位于括号中的参数列表之前   函数调用仅由标识符组成,如果没有声明   对于此标识符是可见的,隐式声明标识符   就像在包含函数调用的最里面的块中一样   宣言

extern int  identifier();
  

出现

当我第一次了解到这一点时,我心里想,“天哪,这根本不是我想要的!”而且,与其他许多人一起,这个“功能”在C99中被改变了。

答案 2 :(得分:0)

Clang是GNU C11模式的默认值,它使用C99语义。在C99中,不再允许隐式函数声明。

你可以使用clang --std=c89clang --std=gnu89将clang置于c89模式,这应该允许这种行为,

请参阅:Are prototypes required for all functions in C89, C90 or C99?