question for preprocessor gurus

im kind of ok on stringification and token pasting, but occasionally my head gets in a spin especially when they are nested, so here goes:

at some point, in one branch of an #ifdef, I want to #include another file. its name depends on the mcu type, so if im compiling for uno, I will have _AVR_IOXXX_H already #defined and equal to iom328p.h

in this case, I want to do the equivalent of

include "my_iom328p.h"

in another universe, id write

include "my_%_AVR_IOXXX_H%"

but that wont cut the mustard here, I know. at least it might make it clearer what I want to do...

prizes (of kudos only, im afraid) for neatest/cleanest/slickest...

ooo, ooo, pre-processor fun......

I'm assuming you meant exactly what you said. So when you said:

I will have _AVR_IOXXX_H already #defined and equal to iom328p.h

That you really meant it and that it is really defined that way so it does not have quotes.

Here is what I came up with: First these helper macros:

#define str(x) #x
#define xstr(s) str(s)
#define _PASTE( _f, _b) _f ## _b
#define _MYHDR(_prefix, _hdr) _PASTE(_prefix, _hdr)
#define MYHDR(_hdrname) xstr(_MYHDR(my_, _hdrname))

Then to use you simply would use:

#include MYHDR(_AVR_IOXXX_H)

This will paste my_ to the name of the header then stringify it

You can of course change the MYHDR or _MYHDR macros to have any prefix that you want or even add a suffix. It does require that the initial define for the header name not be quoted.

--- bill

bill,

wow, now I know why ny head sometimes spins...

I NEARLY said exactly what I meant, first I missed the trailing underscore from AVR_IOXXX_H

these defines are part of the build process the actual code is

define AVR_IOXXX_H "iom328p.h"

( in the file iom328p.h itself)

its 0425 here and I havent had chance to try it yet...wil the presence of quotes affect your solution?

BareMetal:
bill,
.wil the presence of quotes affect your solution?

Yes, it won’t work.

The concatenation available at the pre-processor level just pastes together tokens.
If you have a quotes, the quotes become part of the new token
and then you will end up with a #include that has too many quotations.

Not sure how to do what you want given what you have.

I do a bunch of special things based on processor types in my openGLCD library.
I base my preprocessing decisions, including which headers to include based on the processor type.
So for “uno” type boards that use mega8/168/328 you can check for:

#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)

— bill

I considered that option, but I dont like it for several reasons.

  1. im trying to cope with many mcu and it will quickly get unwieldy
  2. purism AND futureproofing...id rather make the decision based on mcu capability, ie "family" than specific mcu. an example is best:

im handling pinchange interrupts. many mcu use PCICR others use GIMSK. all the types im handling use one or the other. id rather say #ifdef GIMSK... than #if mcu = attiny25 or attiny45 or attiny85 or attiny24 or attiny44 or attiny2313 etc etc for half a page

Any new processor operating same as those others with same features will "just work" with no extra code or effort needed.plus any mcu that I dont know about but has same structure will also just work, whereas if I miss one from the list of 22 or 33 or 44 or 55 etc, it will die instantly. if theres a 25 I never heard of thats a fatter 22 with same core, it will compile and run even tho im blissfully unaware

  1. 90% of the code is common to most mcu. there are odd exceptions, and what I think will be less work is to have a single header that defines the "standard" case and then includes mcu.specifc headers in the "edge" cases, such as the pesky little tiny2313 and 2313a the former is a "standard" case, but the latter has features that none of the other mcu have that im catering for.

in this case, it seems right to include a 2313a specific file which will undef the std case and define its unique version, which is indeed truly mcu specific as opposed to being feature/capability .specific.

the original question was to sort out that last point, by pulling in the e.g. 2313a file when all else fails and only 5% of the code is different, to cope with the A suffix features. ps I lied the 640,1280,2560 are a royal p.I.t.a. with a PCINT block split over two ports...but again, they all have PORTK defined which none of my other many mcu do, so a good way to make the cut dependent on feature rather than mcu is to #ifdef PORTK....

there MUST be a way...my hunt continues!

I hate to say it @BareMetal but you are on a fool’s errand…

http://gcc.gnu.org/onlinedocs/gcc-4.1.2/cpp/Include-Syntax.html

The argument of `#include’, whether delimited with quote marks or angle brackets, behaves like a string constant in that comments are not recognized, and macro names are not expanded. Thus, #include <x/*y> specifies inclusion of a system header file named x/*y. …

The KISS principle seems apposite here.

This was one of the things that changed in gcc back between version 2.7 and version 4.x, much to our annoyance at We had these lovely macros that would piece together a #include filename from various components, and they all stopped working :frowning: Thousands of files worth, probably !

#include “my_iom328p.h”

This seems like a bad idea. Wouldn’t you need a my_xxx file for every possible target? How is that better than needing to add a #if case for each target?

@badly...no shame in telling me its a fools errand, its exactly why im here asking, so I dont hurt my brain too much more

@west n michiyon

maybe my long reply to bill was badly worded...its exactly KISS and avoiding a million mymcu999.h files why I need this feature. 90% of th3 code works for mcu by determining its ports n egisters with ifdefs and compile.time constants, thus I KISS by having one file for half a billion mcu types. in the 10% where a particular mcu is quirky, eg 2313A...note the A..the bare2313 is fine...I needmto pull in additional mcu.specific includes to cope with the quirks. ultimately they may only be 2 or 3 extra mcu specific header files.

Sorry if thats not what you thought I said earlier...it was very very late when I wrote it.

macro names in a #include argument are expanded.
i.e. this works:

#define HFILE "file.h"
#include HFILE // comment goes here

BareMetal,
I understand what you are wanting to do and the use for it.
I’m just not sure that it can be done since I don’t think the pre-processor
can combine quoted “strings” since it can only do simple token pasting/concatenation.
i.e. it can’t combine “foo”“bar” into “foobar”
The compiler can do this as it understands strings but #include processing
is handled by cpp.

— bill

Unfortunately the pasting together of adjacent strings happens in a later phase than handling the preprocessing directives. I suspect I am the closest to a Guru that you will get on this forum. I was a member of the ANSI C committee that created the first C standard (ANSI C89 replaced by ISO C90), though with a change of jobs in 1994, I stopped participating in the standards process.

Section 5.1.1.2 of the C99 standard (I don’t have a C11 standard online) defines the order of translation:

  • Files read and translated into the source character set;
  • Backslash followed by newlines are removed;
  • Source text is converted to tokens, comments replaced by a single space character;
  • Preprocessing is done;
  • Translation of the <y> sequences to the appropriate by in the target environment is done;
  • Adjacent string literals are joined together;
  • The rest of the compilation occurs.

Now, Arduino uses C++ instead of C, but I believe it uses a similar phases of translation.

sigh.

thanks guys

define BRAIN 13

digitalWrite(BRAIN,LOW)

Can’t you sort of do what you want with some thing like this:

#if define(XXX) || defined(YYY)
#define HFILE "header1.h"
#elif defined(ZZZ)
#define HFILE "header2.h"
#else
#define HFILE "header3.h"
#endif

#include HFILE

Where XXX/YYY/ZZZ etc… might be things like, PCICR, GIMSK, PORTK etc…
or even a check for a specific processor define.

— bill

bperrybap: Can't you sort of do what you want with some thing like this:

#if define(XXX) || defined(YYY)
#define HFILE "header1.h"
#elif defined(ZZZ)
#define HFILE "header2.h"
#else
#define HFILE "header3.h"
#endif

Yes, what you can't do is paste together quoted strings and use it in an #include statement. Of course if you are going to do this enumeration, you might as well do:

#if define(XXX) || defined(YYY)
#include "header1.h"
#elif defined(ZZZ)
#include "header2.h"
#else
#error "Unknown machine"
#endif

Note, it is likely that using #ifdef's in this manner will confuse the poor little IDE that attempts to preprocess the .ino/.pde files to make C++ somewhat easier for newbies to use, and you likely will need to use either raw Makefile or something like Eclipse that doesn't run the Arduino IDE. You will need to properly add forward references and include of the Arduino header files.

you guys are honing in on the kssue like bloodhounds. bills suggestion is kind of how io.h does it, and its what im grying to avoid as with 20.odd mcu im trying to handle it gets unwieldy fast.

also, bperrybap, thats exactly why im doing the work in atmel studio right now, to avoid any arduino complications. once the gremlins are out, I will then add an arduino.compatible library, so that newbies can say

include "gpPCINT.H"

define ENCA 10

define ENCB 12

class myEncoder: public gpAbstractEncoder { ... }

myEncoder::onFwd(){ ...blink faster...} myEncoder::onBwd(){ ...blink slower and go "ping"...}

myEncoder alps(ENCA,ENCB);

etc. thats the goal and as long as its an avr mcu target, you will get a nice clean debounced, interrupt driven button, encoder, heart monitor, mars rover "for free" with the nasty guts hidden.

its a beaytiful dream....thwarted only by a recalcitrant preprocessor. I will find another way...I know I can dot severalmhard ways, im just a bit of a penickety minimalist purist, seeking the most compact code, the occams razor...

sometimes I csn spend five times longer, finding the "quicker" way... I love it!

BareMetal: you guys are honing in on the kssue like bloodhounds. bills suggestion is kind of how io.h does it, and its what im grying to avoid as with 20.odd mcu im trying to handle it gets unwieldy fast.

I wasn't suggesting normally using MCU types, but rather to use defines that exist within the included i/o headers. That way you can drastically narrow down the conditionals. Then only use CPU specific defines for special cases, as in the case of the 2313a you mentioned.

also, bperrybap, thats exactly why im doing the work in atmel studio right now, to avoid any arduino complications. once the gremlins are out, I will then add an arduino.compatible library, so that newbies can say

The arduino IDE doesn't parse or mess with .h files so you can do whatever you want in your header. It only does it's goofy parsing on .pde & .ino files.

Just as a point of reference, when I test/debug complex macros, I typically initially don't do it in the embedded environment. It is much easier to just do it from the command line using the native gcc compiler - at least it is if you are using a *nix operating system. It is often very useful in debugging to be able to see the pre-processor output without invoking the actual compiler.

its a beaytiful dream....thwarted only by a recalcitrant preprocessor. I will find another way...I know I can dot severalmhard ways, im just a bit of a penickety minimalist purist, seeking the most compact code, the occams razor...

sometimes I csn spend five times longer, finding the "quicker" way... I love it!

It is a bit of a odd thing to want to do in the pre-processor. In my 30 years of using C for real-time f/w embedded development, I've never had a need to do what you are wanting to do. Perhaps an alternate approach is needed?

im not trying to "do" anything in the preprocessor, I justcwant to use it to its max to set up compile time constants so that my general purpose code has everything in place.

almost all of what it does is hw register specific and thus I want to make sure the correct registers for the mcu are in place prior to compile. an example...pseudocode, im on a tablet and correct syntax is a pain..

objective: register the interrupt n strategy: set bit in ctrl register to allow ints for the block that maps to pcint n dtetermine mask register that maps pcint n set bit in mask to allow int n

pseudocode for 328, tiny48, 2560 etc etc..any mcu using PCICR PCICR |=_BV(PCIEx) // x depends on n, usually int.truncated n/8 PCMSKy |= _BV(n) // y dpends also on n, usually n%8 savedPort=PORTz // z depends on mcu and n

pseudocode for tiny24,44,2313 etc etc or any mcu using GIMSK GIMSK |=_BV(PCIEx) // x depends on n, usually int.truncated n/8 PCMSKy |= _BV(n) // y dpends also on n, usually n%8 may well be different for this mcu from y above etc savedPort=PORTz // different z per mcu of course and not same as above..

at its most abstract, I want x=pcint2PCIEnumber(n) y=pcint2PCKMSKnumber(n) z=pcint2PORT(n) %REG |= _BV(x) // or bv on PCIE%x, I dont mind PCMSK%y .... savedPort=PORT%z

etc where im using % as a conceptual tag for a replaced parameter

providing that my header defines the appropriate macros or functions for the mcu specific pcint2xxx routines and sets the %x y and z for the mcu, then that one piece of code will compile and work for whatever mcu is selected.

I know thats a very loose theoretcial explanation, but I hate typing on my tablet, and im sure you know where im coming from.

To me, that seems to be a proper, sensible and fairly common use of the preprocessor...its what some arduino cores do for things like digitalPinToPCICR, digitalPinToPCMSKBit etc..which do pretty much what I want to do, but NOT for arduino digital pins, for PCINT numbers. there are no corresponding GIMSK ....why would there be, arduino doesnt make any tiny45 or 2313 boards..but I do and I want a single library that will compile for all my targets. is it such a big ask...im 95% there already, I was just fitting in these lsst few edge cases when i had my idea about automatically pulling in mcuxxx.h files...

I think I need to take my php python hat off where everything is included at runtime and be tweaked within an inch of its life or even have parameters edited in and then eval'd...dont cringe!