2
votes

Let's analyze the following code example:

int main() {
    return func();
}

int func() {
    return 1;
}

Clang will report error:

/private/tmp/src.cpp:2,9 - Error - use of undeclared identifier 'func'

But i can find lot's of such errors in wide used examples, f.e. some arduino sources: 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

Though function is used before defined that code can be compiled with GCC successfully. How that can be? Is it different Clang and GCC behavior? Are there any flags to allow this for Clang?

PS. Here is successful command line to compile the code used by 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.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/variants/mega -I/Applications/Arduino.app/Contents/Resources/Java/libraries/Servo/src -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/libraries/Wire -I/Applications/Arduino.app/Contents/Resources/Java/libraries/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
There are flags for both that can affect how "picky" the compilers are. IANALL, but I believe forwards definitions of this type are not allowed in (later) C++ specs (hence the error from Clang) but were very common in possibly older C++; definitely old C (such a function was assumed to return int). Because there's lots of old code that was written this way, I'm guessing gcc chose to allow them (though I'd be slightly surprised if it didn't issue a warning).TripeHound
what are the flags to make Clang work like GCC in this case?4ntoine
I don't know: I've never used it. However, this page on Clang compatibility says "Clang is more strict than other popular compilers, and may reject incorrect code that other compilers allow" so there may not be an option for what you want. You may have to fix the code by using prototypes.TripeHound

3 Answers

4
votes

This is actually not to do with the compiler, but the Arduino IDE. The IDE has a preprocessing step which forward-declares all the defined functions so that you don't need to worry about function placement in the file.

My strong recommendation would be to just follow the language rules and forward-declare your functions or define them before their use. Your code will be more portable and understandable for it.

1
votes

No, you don't want clang to behave like gcc in this regard. In fact, use -Wall and -W (or -Wextra) in order to get gcc and clang both to give you even more warnings.

But i can find lot's of such errors in wide used examples

Sadly, getting C and C++ right is so hard that widely used examples are not good enough.

Your example includes a bug that arguably has no real effect on this program. EDIT: it appears that the IDE is clever enough to workaround language features. Refer to @TartanLlama's answer for details. Perhaps the author could make the claim that it's by design. But it's so rarely the case that clang thankfully saves you from yourself.

C89 §3.3.2.2, "Function calls" includes:

If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration

extern int  identifier();

appeared

When I first learned that, I thought to myself, "OMG that's not what I wanted at all!" And, so it went with so many other folks that this "feature" was changed in C99.

0
votes

Clang is per default in GNU C11 mode which is uses C99 semantics. In C99 the implicit function declaration is not allowed anymore.

you can put clang into c89 mode with clang --std=c89 or clang --std=gnu89 which should allow that behavior,

See: Are prototypes required for all functions in C89, C90 or C99?