# Preprocessor problem

**URL:** <https://forum.arduino.cc/t/preprocessor-problem/696970>\
**Category:** Programming\
**Created:** [February 20, 2021, 10:36am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970 "2021-02-20T10:36:47Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 20, 2021, 10:36am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/1 "2021-02-20T10:36:47Z")

</div>

Hi!  
I'm facing a strange problem...  
On my main ino file, on first line, i have a definition:

```cpp
#define MYDEF

#include "Ethernet.h"

```

Then i include the ethernet library, modified in this way:

```cpp
#ifndef	W5100_H_INCLUDED
#define	W5100_H_INCLUDED

#define SPI_ETHERNET_SETTINGS SPISettings(14000000, MSBFIRST, SPI_MODE0)
#pragma message "14"
...

#if defined(MYDEF)
#pragma message "4"
#undef SPI_ETHERNET_SETTINGS
#define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0)
#endif

...
#endif

```

And this is the output of the compiler:

```cpp
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src/utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src/utility/w5100.h:54:17: note: #pragma message: 4
 #pragma message "4"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\EthernetClient.cpp:24:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\Dhcp.cpp:7:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\Dns.cpp:8:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\Ethernet.cpp:23:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\EthernetICMP.h:32:0,
                from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\EthernetICMP.cpp:42:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\EthernetServer.cpp:23:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\EthernetUdp.cpp:32:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\socket.cpp:23:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility/w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"
                ^
In file included from C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility\w5100.cpp:13:0:
C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src\utility\w5100.h:23:17: note: #pragma message: 14
 #pragma message "14"

```

Why the first time the preprocess do what is expected, then simply skip the #if condition??  
And also: if the first time it set the

```cpp
W5100_H_INCLUDED

```

Why the subsequent times it ignores the

```cpp
#ifndef	W5100_H_INCLUDED

```

and compute the #pragma?

The end result is that it uses the wrong SPI\_ETHERNET\_SETTINGS...

I'm simply trying to reduce the SPI speed for the transactions with the ethernet module.

Thanks for the help!

---

<div class="post-metadata">

**Author:** ![6v6gt](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/6v6gt/32/225488_2.png) [@6v6gt](https://forum.arduino.cc/u/6v6gt)\
**Post date:** [February 20, 2021, 11:28am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/2 "2021-02-20T11:28:16Z")

</div>

This w5100.h file is located in same folder/directory as your .ino file ?  
That is, your .ino file located under: C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src/utility/ ?

---

<div class="post-metadata">

**Author:** ![pert](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/pert/32/217111_2.png) [@pert](https://forum.arduino.cc/u/pert)\
**Post date:** [February 20, 2021, 11:42am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/3 "2021-02-20T11:42:20Z")

</div>

The reason for this is that the .ino file of your sketch is a separate "translation unit" from the .cpp files of the Ethernet library.

When you compile your sketch, the .cpp files of the Ethernet library are also compiled. The #include directive is essentially the equivalent of just copy pasting the entire contents of the .h file where the #include directive is. So the contents of Ethernet.h is compiled in multiple translation units. The #defines from one translation unit have no effect on another translation unit. So MYDEF is defined when Ethernet.h is compiled as part of your sketch file, but it is not defined when Ethernet.h is compiled as part of Ethernet.cpp. This is why the conditional compilation is done differently for each translation unit.

This is why people get all excited about not being able to add -D flags to the compiler commands. The -D  
flag allows you to define macros for all translation units, which is not possible when using a #define directive in your sketch (unless the sketch is the only translation unit).

---

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 20, 2021, 12:21pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/4 "2021-02-20T12:21:43Z")

</div>

> 6v6gt:  
> This w5100.h file is located in same folder/directory as your .ino file ?  
> That is, your .ino file located under: C:\Users\xxx\Documents\Arduino\libraries\Ethernet\src/utility/ ?

No, different folders

> pert:  
> The reason for this is that the .ino file of your sketch is a separate "translation unit" from the .cpp files of the Ethernet library.
> 
> When you compile your sketch, the .cpp files of the Ethernet library are also compiled. The #include directive is essentially the equivalent of just copy pasting the entire contents of the .h file where the #include directive is. So the contents of Ethernet.h is compiled in multiple translation units. The #defines from one translation unit have no effect on another translation unit. So MYDEF is defined when Ethernet.h is compiled as part of your sketch file, but it is not defined when Ethernet.h is compiled as part of Ethernet.cpp. This is why the conditional compilation is done differently for each translation unit.
> 
> This is why people get all excited about not being able to add -D flags to the compiler commands. The -D  
> flag allows you to define macros for all translation units, which is not possible when using a #define directive in your sketch (unless the sketch is the only translation unit).

That explain all. the first occurrence is evaluated as originated from my ino, but the other libraries that call the same include get a whole new set of definitions.  
So, what's the purpouse of #ifndef in the beginning of every H files?  
Can this impact the code optimizations, as the same function are included over and over?  
Thanks for the explaination!

---

<div class="post-metadata">

**Author:** ![pert](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/pert/32/217111_2.png) [@pert](https://forum.arduino.cc/u/pert)\
**Post date:** [February 20, 2021, 12:32pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/5 "2021-02-20T12:32:30Z")

</div>

> masterx81:  
> So, what's the purpouse of #ifndef in the beginning of every H files?

The are known as "[include guards](https://wikipedia.org/wiki/Include_guard)". Their purpose is to prevent the header file content from being included multiple times in the same [translation unit](https://wikipedia.org/wiki/Translation_unit_(programming)), which would cause a compilation error. But they allow the inclusion once in each translation unit, which is exactly what you want them to do.

> masterx81:  
> the same function are included over and over?

Header files traditionally only contain declarations. There are some exceptions of inline function definitions, and these can have an impact on optimization.

Probably not appropriate for the Ethernet library, but related to this subject you might be interested in the approach used in the Encoder library:

> <https://github.com/PaulStoffregen/Encoder/blob/1.4.4/examples/NoInterrupts/NoInterrupts.ino#L7-L14>

This might seem odd at first, since you just discovered that attempting to control conditional compilation of libraries via `#define` directives in the sketch doesn't work so well.

The reason it's possible with the Encoder library is because the author put all the relevant source code in `Encoder.h`:

[https://github.com/PaulStoffregen/Encoder/blob/1.4.4/Encoder.h](https://github.com/PaulStoffregen/Encoder/blob/1.4.4/Encoder.h)

So the sketch's translation unit contains the library source code that is being controlled by the macro defined in the sketch.

---

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 20, 2021, 12:46pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/6 "2021-02-20T12:46:08Z")

</div>

So i have no way to force a compilation condition on another module, that will be always evaluated.  
And i suspect that also the already present conditional definitions in the ethernet library aren't evaluated.  
IE:

```cpp
#if defined(ARDUINO_ARCH_ARC32)
#undef SPI_ETHERNET_SETTINGS
#define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE0)
#endif

```

would be nice a way to declare a "global define" that is always evaluated... (as the -D flags seem to do)

---

<div class="post-metadata">

**Author:** ![pert](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/pert/32/217111_2.png) [@pert](https://forum.arduino.cc/u/pert)\
**Post date:** [February 20, 2021, 1:58pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/7 "2021-02-20T13:58:21Z")

</div>

> [@masterx81](#):
>
> i suspect that also the already present conditional definitions in the ethernet library aren't evaluated.  
> IE:
> 
> ```cpp
> #if defined(ARDUINO_ARCH_ARC32)
> #undef SPI_ETHERNET_SETTINGS
> #define SPI_ETHERNET_SETTINGS SPISettings(8000000, MSBFIRST, SPI_MODE0)
> #endif
> 
> ```

Board identification macros like ARDUINO\_ARCH\_ARC32 are defined via a -D flag in the compilation commands, so it is defined in every translation unit.

> [@masterx81](#):
>
> a way to declare a "global define" that is always evaluated

There are ways to do it, but only via the Arduino IDE's command line interface or by modifying the configuration of the Arduino boards platform. You can see prior discussion about that by following the links off this proposal:

> <https://github.com/arduino/arduino-cli/issues/846>
>
> \### Describe the request
> 
> Establish two sets of standard "extra flags" build p…roperties:
> 
> \- one set for use by platform developer
> \- one set for use by the user
> 
> These should be clearly documented as being dedicated to the exclusive use by either the platform developer or the user.
> 
> The properties proposed here are only arbitrary properties, without any special use by the build system, so no changes would required in the build system. It is only a matter of setting an example for 3rd party platform developers by adding these additional properties to the \`platform.txt\` files of the official platforms with comments clearly explaining their intent.
> 
> Ideally, the properties would be documented in the \[Arduino platform specification\](https://arduino.github.io/arduino-cli/latest/platform-specification/) as well (https://github.com/arduino/arduino-cli/issues/985).
> 
> 
> \### Describe the current behavior
> 
> Arduino has established a convention of providing "extra flags" properties in \[\`platform.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#platformtxt). These properties are intended to allow the compilation process to be customized by the addition of arbitrary flags in the compilation commands.
> 
> For example:
> 
> https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L39-L49
> 
> \`\`\`text
> \# This can be overridden in boards.txt
> build.extra\_flags=
> 
> \# These can be overridden in platform.local.txt
> compiler.c.extra\_flags=
> compiler.c.elf.extra\_flags=
> compiler.S.extra\_flags=
> compiler.cpp.extra\_flags=
> compiler.ar.extra\_flags=
> compiler.objcopy.eep.extra\_flags=
> compiler.elf2hex.extra\_flags=
> \`\`\`
> 
> These properties are referenced in the appropriate compilation recipes in \`platform.txt\` (\[example\](https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/platform.txt#L58)).
> 
> The empty definitions in \`platform.txt\` ensure that if the extra flags are not defined elsewhere, the compilation recipes referencing them will still work. Those default empty definitions can be overrriden from any of the other platform configuration files:
> 
> \- \[\`boards.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt)
> \- \[\`boards.local.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#boardslocaltxt)
> \- \[\`platform.local.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#platformlocaltxt)
> \- \[\`global platform.txt\`\](https://arduino.github.io/arduino-cli/latest/platform-specification/#global-platformtxt)
> 
> or from the command line:
> 
> \- \[\`arduino-cli compile --build-property\`\](https://arduino.github.io/arduino-cli/latest/commands/arduino-cli\_compile/#options) 
> \- \[\`arduino --pref\`\](https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options)
> 
> \---
> 
> From the comments in the official \`platform.txt\` files, it seems that \`build.extra\_flags\` is intended to be for the use of the boards platform developer, while the other "extra flags" properties are intended to be for the use of the user (because a platform developer has no need for \`platform.local.txt\`).
> 
> A common use case of these properties for the user would be to add \`-D\` flags (e.g., https://github.com/arduino/arduino-cli/issues/210#issuecomment-493892258, https://github.com/arduino/Arduino/issues/6344), but there are other uses.
> 
> However, platform developers sometimes use these properties in their \`boards.txt\` file (\[example\](https://github.com/MCUdude/MightyCore/blob/v2.0.5/avr/boards.txt#L103-L111)). This presents the problem that the user risks inadvertently overriding the flags defined by the boards platform if they use the "extra flags" properties to modify the compilation command (\[example\](https://github.com/arduino/arduino-cli/issues/2041)).
> 
> \### Arduino CLI version
> 
> N/A
> 
> \### Operating system
> 
> All
> 
> \### Operating system version
> 
> Any
> 
> \### Additional context
> 
> \#### Re: Possible Harmful Effect on APIs
> 
> On a certain level, this does provide the user the global macro setting capability that has been often requested, and often rejected: 
> 
> \- https://github.com/arduino/arduino-builder/issues/15
> \- https://github.com/arduino/arduino-builder/pull/29
> \- https://github.com/arduino/arduino-builder/pull/282
> \- https://github.com/arduino/arduino-builder/issues/283
> \- https://github.com/arduino/arduino-builder/issues/354
> \- https://github.com/arduino/arduino-ide/issues/1837
> \- https://github.com/arduino/Arduino/issues/421
> \- https://github.com/arduino/Arduino/issues/2547
> \- https://github.com/arduino/Arduino/issues/3635
> \- https://github.com/arduino/Arduino/pull/3717
> \- https://github.com/arduino/Arduino/pull/3757
> \- https://github.com/arduino/Arduino/issues/4528
> \- https://github.com/arduino/Arduino/issues/5084
> \- https://github.com/arduino/Arduino/issues/5390
> \- https://github.com/arduino/Arduino/issues/7189
> \- https://github.com/arduino/Arduino/issues/11108
> \- https://github.com/arduino/arduino-cli/issues/159
> \- https://github.com/arduino/arduino-cli/issues/210
> \- https://github.com/arduino/arduino-cli/pull/1117
> \- https://github.com/arduino/arduino-cli/pull/1517
> \- https://github.com/arduino/tooling-rfcs/issues/9
> \- https://github.com/arduino/tooling-rfcs/issues/22
> 
> However, I think this proposal strikes the right balance of:
> 
> \- Allowing advanced users to do advanced things
> \- Not exposing standard users to additional complexity that makes the Arduino development software less beginner friendly
> \- Being very easy for Arduino to implement
> 
> The concern has been that allowing users to set global macros will result in library developers unnecessarily using these as part of the API, making that API less beginner friendly (https://github.com/arduino/arduino-builder/issues/15#issuecomment-145558252). However, if the user is required to use a command line interface or create a specially formatted configuration file in a difficult to access location, the average user won't be interested, and so it will only make sense for a library developer to use this feature for advanced, rarely used features of the library (e.g., enable debug output for troubleshooting of the library). We have already had this "extra flags" capability \[since 2014\](https://github.com/arduino/ArduinoCore-avr/commit/2b9f022eaad0d107b1516c22ac02bdac4977223b), yet I haven't seen it result in any significant incorporation of user set global macros into the user-level API of Arduino libraries.
> 
> \### Issue checklist
> 
> \- \[X\] I searched for previous requests in \[the issue tracker\](https://github.com/arduino/arduino-cli/issues?q=)
> \- \[X\] I verified the feature was still missing when using the latest \[nightly build\](https://arduino.github.io/arduino-cli/dev/installation/#nightly-builds)
> \- \[X\] My request contains all necessary details

But you can't define macros globally from a sketch, and this is by design. The Arduino developers are concerned that if this capability was provided, library authors would start incorporating it into the standard user interfaces. As we can see from the discussion here, the preprocessor is very confusing. I only know what I know because I ran into this same perplexing behavior you reported and spent quite some time tearing my hair out before I learned about this concept of "translation units". While it's an important thing to learn eventually, it's not something a beginner should be subjected to. For them, something like this is much more intuitive:

```cpp
SomeLibrary.begin(someConfigurationValue);

```

---

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 20, 2021, 2:20pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/8 "2021-02-20T14:20:01Z")

</div>

Ok, perfect all clear... Can't be explained better! I'm a .net asp/vb developer, quite new to the C++/arduino world, so this problems were totally counterintuitive to me... It's important to know this limitation.  
In any case i'm more concerned about the code optimization (in small equipped flash/ram devices as the mcu's): when the compiler process more times the same prototype function definition / variables (every time that it encounter the same include in different "translation units"), he know that actually they are the same things? Because i've noticed that with exactly the same code, playing moving functions in different includes, the flash usage was changing - while the compiled code was doing exacly the same.

---

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 21, 2021, 9:50am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/9 "2021-02-21T09:50:39Z")

</div>

One more thing, how i know what -D flag the compiler is actually using?

---

<div class="post-metadata">

**Author:** ![pert](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/pert/32/217111_2.png) [@pert](https://forum.arduino.cc/u/pert)\
**Post date:** [February 21, 2021, 11:53am UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/10 "2021-02-21T11:53:06Z")

</div>

> masterx81:  
> In any case i'm more concerned about the code optimization (in small equipped flash/ram devices as the mcu's): when the compiler process more times the same prototype function definition / variables (every time that it encounter the same include in different "translation units"), he know that actually they are the same things?

I can tell you that the compiler is very good at optimizing the code. But certainly the choices you make when programming can play a role too. As for getting in to the specifics of your question, I'm not really the best one for that. But there are some super C++ wizards here on the forum I'm sure can step in and give you the lowdown.

> masterx81:  
> how i know what -D flag the compiler is actually using?

Do this:

- File \> Preferences
- Check the box next to "Show verbose output during: Compilation".
- Click the "OK" button.
- Compile a sketch.

After compilation finishes, scroll up the black console window at the bottom of the Arduino IDE window. There you will see all the compilation commands the Arduino IDE ran to compile your sketch. These commands contain the -D flags.

There is an exception to what I said above for certain boards. For example, if you're compiling for the Arduino Nano 33 BLE, you'll see something like this in the compilation commands:

```arduino
"@C:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed\\1.3.2\\variants\\ARDUINO_NANO33BLE/defines.txt"

```

This @ tells the compiler to add the contents of the file at that path as flags. You can see the contents of the file here:

> <https://github.com/arduino/ArduinoCore-mbed/blob/main/variants/ARDUINO_NANO33BLE/defines.txt>

This particular one contains a large collection of -D flags that would have made the compilation commands too long if they were used in the traditional manner directly in the command line.

---

<div class="post-metadata">

**Author:** ![masterx81](https://avatars.discourse-cdn.com/v4/letter/m/bbce88/32.png) [@masterx81](https://forum.arduino.cc/u/masterx81)\
**Post date:** [February 21, 2021, 12:40pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/11 "2021-02-21T12:40:20Z")

</div>

Whoa!  
Thanks for all, you have put some light on some unclear (and not so well documented) aspects of the arduino environment!

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [June 21, 2021, 12:40pm UTC](https://forum.arduino.cc/t/preprocessor-problem/696970/12 "2021-06-21T12:40:46Z")

</div>

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.
