Macro trouble

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I'm having trouble getting some macros working properly. I could break down the problem to the following program:

#include 

// Get Bit Defination Of Symbol
#define io_bit(port, bit)   (P ## port ## bit)

// Assign Symbol IO_PIN To Pin PC7 Of PORTC
#define IO_PIN              C, 7


int main (void)
{
    // Toggle Pin
    PINC = (1 << io_bit (IO_PIN));
    
    while (1);
    
    return 0;
}

I expect that the code line in the main is preprocessed to:

PINC = (1 << PC7);

But I always get the following error when I try to compile the program above:

main.c:13:32: error: macro "io_bit" requires 2 arguments, but only 1 given
main.c: In function 'main':
main.c:13: error: 'io_bit' undeclared (first use in this function)
main.c:13: error: (Each undeclared identifier is reported only once
main.c:13: error: for each function it appears in.)
make.exe: *** [main.o] Error 1

So I'm doing something wrong. But I just can't see what's the problem.

Thanks for your help!

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First thing to do is to run only the CPP (the C PreProcessor) and inspect what it generates (what the compiler proper sees). The error message you are getting is from the compiler proper, and it will probably help you to see what the compiler sees.

I don't have the switch to give to avr-gcc for getting the CPP output in my head at the moment, but you'll find it in the gcc documentation. It might be -E or -F, but I'm far from sure).

I fail to see the benefits of what you want to do though. Fact is that you could name any existing "port character" when calling the macro, but it will not affect the port actually modified.

Eg, if you mess up and do

#define IO_PIN   A, 7
.
.
.
   PINC = (1<<io_bit(IO_PIN));

then how did that make things clearer?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I fail to see the benefits of what you want to do though.
I agree. How is this better than simply:

#define IO_PIN PC7

Regards,
Steve A.

The Board helps those that help themselves.

Last Edited: Wed. Apr 28, 2010 - 07:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You use gcc -E to pre-process the file.

I have a rule in my makefile to "make file.i"

Yes, it can be handy to paste macros together. However you need to do it in two stages:

#define PASTE(x, y)	x ## y
#define B(x, y)	PASTE(x, y) 

like this:

#define IO_PIN   B(P, B(C, 7))

But I cannot help feeling that a simple

#define IO_PIN   PC7

is a lot simpler.

You can build the different USART sfr and bit names by judicious use of pasting. Or build PORT, DDR, PIN names.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
First thing to do is to run only the CPP (the C PreProcessor)
I tried that already. But when I run make main.i I already get an error from the CPP:
main.c:13:32: error: macro "io_bit" requires 2 arguments, but only 1 given

So I don't have a main.i file to look at.

Quote:
I fail to see the benefits of what you want to do though.
Don't think about it. I only use it here in this example. I removed all other macros except io_bit() to make clear where the problem is.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want to screw the preprocessor you have to screw it the right way:

#define pglue(a, b)  P ## a ## b
#define io_bit(c)    pglue(c)

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I forgot to note that when I replace

PINC = (1 << io_bit (IO_PIN));

with

PINC = (1 << io_bit (C, 7));

The program is compiled just fine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ArnoldB wrote:
If you want to screw the preprocessor you have to screw it the right way:

#define pglue(a, b)  P ## a ## b
#define io_bit(c)    pglue(c)

Thanks, that works just fine. Now explain your macro, please. I still don't get it.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Put yourself in the position of CPP. it will

    PINC = (1 << io_bit (IO_PIN));
    PINC = (1 << io_bit (C, 7));
    PINC = (1 << pglue (C, 7));
    PINC = (1 << P ## C ## 7);
    PINC = (1 << PC7);
    ...

Actually the PINC amd PC7 will get substituted too.

Try and do the same exercise with your original method.
You can see that the argument count goes wrong.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is how I understand my code:

PINC = (1 << io_bit (IO_PIN));
PINC = (1 << io_bit (C, 7));
PINC = (1 << (P ## C ## 7));
PINC = (1 << PC7);
... 

But I'm wrong...
I just don't understand, how pglue() makes the difference.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S-Sohn wrote:
Quote:
First thing to do is to run only the CPP (the C PreProcessor)
I tried that already. But when I run make main.i I already get an error from the CPP:
main.c:13:32: error: macro "io_bit" requires 2 arguments, but only 1 given

So I don't have a main.i file to look at.

I wrote:
The error message you are getting is from the compiler proper

which was just plain wrong. Sorry for the confusion.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S-Sohn wrote:
Now explain your macro, please. I still don't get it.
It heavily relies on the finer details of macro expansion and replacement.

In

#define io_bit(c) pglue(c)
#define IO_PIN C,7

io_bit(IO_PIN);

the expansion of IO_PIN in io_bit(IO_PIN) is counterintuitive. It is not expanded before io_bit() is expanded. You don't get an intermediate step io_bit(C,7). For the preprocessor io_bit(IO_PIN) is a function macro invocation with one argument IO_PIN, not two arguments C, 7. Only after the macro invocation happened the preprocessor care about the contents, not just the number, of arguments.

The argument IO_PIN is first expanded when the corresponding parameter c in the replacement list of io_bit() is used. So pglue(c) becomes pglue(C,7). It is not pglue(IO_PIN) any more. pglue(C,7) is further evaluated according to preprocessor rules, meaning it is expanded.

Stealing Proteus doesn't make you an engineer.

Last Edited: Wed. Apr 28, 2010 - 08:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have skipped the pglue() step.
So io_bit() appears to have two arguments.

If you had the pglue() step:
This substitutes pglue(x) for io_bit(x)

It cannot do anything further with the 'x' but it can substitute the macro name.

Believe me, these macro expansions can get a little hairy to follow. Which is why I always inspect file.i if I have a problem.

The nested PASTE() of my original example can ensure the correct order of the expansion. It will always try and substitute from the inside of nested parentheses outwards. Just the same as rules for evaluating arithmetic expressions. Except that after each substitution, it looks at the whole line again to see if it can make any more substitutions.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
So io_bit() appears to have two arguments.
No, it doesn't.

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ArnoldB, thanks a lot for your help!!!

I had to read your explanation 10 times.
This isn't trivial stuff.
But now I think I got it.

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the link!

Quote:
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens.

Regards
Sebastian