Why is this C macro causing syntax error?

2.3k views Asked by At

This is the first time I'm using macros in C and I'm trying to replace a large section of code that I'd normally place into a function with a macro. This is a part of an interrupt which will be used quite often and therefore I need to optimize it as much as I can. After reading the documentation, I've seen that the compiler doesn't support function inlining and I want to avoid the function call overhead.

The code itself sends data to a serial-in parallel-out shift register and as far as I can see, there's no shorter way to write the piece of code I need.

I'm using C18 compiler version 3.41 and MPLAB X IDE.

So here's the code I'm using in function form:

void first_one(void)
{
   //3 invisible zeroes
            LATBbits.LATB1=0; //data set to zero

            LATBbits.LATB0=1;//first clock
            LATBbits.LATB0=0;

            LATBbits.LATB0=1;//second clock
            LATBbits.LATB0=0;

            LATBbits.LATB0=1;//third clock
            LATBbits.LATB0=0;
            //end of invisible zeroes

            //two visible zeroes    
            LATBbits.LATB0=1;//first clock
            LATBbits.LATB0=0;

            LATBbits.LATB0=1;//second clock
            LATBbits.LATB0=0;
            //end of two visible zeroes

            LATBbits.LATB1=1;//Data is now one

            LATBbits.LATB0=1;
            LATBbits.LATB0=0;
            //one 

            LATBbits.LATB1=0;//Data is now zero

            LATBbits.LATB0=1;//first clock
            LATBbits.LATB0=0;

            LATBbits.LATB0=1;//second clock
            LATBbits.LATB0=0;

            //after this, everything should be in place
            LATBbits.LATB0=1;
            LATBbits.LATB0=0;
}

I've turned the function into this macro:

#define first_one() {  \
\
            LATBbits.LATB1=0;\               
                              \
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
                                \
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
                            \
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
            \                                
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
\
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
            \
            LATBbits.LATB1=1;\
\
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\    
\
            LATBbits.LATB1=0;\
             ^^^ The syntax error is here!
\
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
\
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
\
            LATBbits.LATB0=1;\
            LATBbits.LATB0=0;\
\
                     }

So what am I doing wrong?

Update: I removed the comments and am now getting a syntax error in a different location.

4

There are 4 answers

3
ouah On BEST ANSWER

Check there is no spaces after the \ tokens, some compiler issue a compile error for this.

4
James McNellis On

Lines are spliced before comments are removed, so the \ in \//3 invisible zeroes does does not continue the line.

You need either to remove the comment or use a C-style comment (/* 3 invisible zeroes */) and place the comment before the \ that continues the line.

0
John Wheal On

The problem is with the comments and the way the preprocessor deals with them. Remove the comments and this should work fine. Alternativly use /* Comment */

4
John Bode On

Three suggestions:

First, make sure that there aren't any trailing spaces after each \.

Second, drop the () from the macro name if it's not meant to take any arguments. edit struck per comments below.

Finally, wrap the contents of the macro in a do {...} while(0) (with no trailing semicolon). This way, when you write first_one(); in your code, you won't have a spurious semicolon after the closing brace.

In short,

#define do_first         \
  do {                   \
    LATBbits.LATB0 = 1;  \
    ...                  \
  } while(0)

edit Lundin points out that this is old-fashioned and unnecessary. I always believed it was required to avoid a diagnostic if a macro expanded to a statement of the form {...}; -- apparently I was wrong. I still prefer it as a stylistic choice, though.