0

I came across a #define statement with the following expression. I do not understand what do the whole statement or the comma do that separate the 2 expressions within the parentheses. It seem like a function, I guess it is not.

#define LCD_SELECT_CS1 (PORTD |= (1<<3), PORTD &= ~(1<<2))
sunny
  • 51
  • 1
  • 10

3 Answers3

1

Comma in C is just a sequential operator for expressions and construction an expression. That means that:

e1, e2, ..., en

is an expression whose value is the expression of en and evaluates e1, then e2, ... then en

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

I guess there are two questions here:

  1. What does it do / How does it work?
  2. Why was it written this way?

How it works is by use of the comma operator, which is probably C's least-used operator. It basically means, "first do the first thing, then do the second thing." It is not the same (even though it looks the same) as the commas separating the arguments in a function call, or the commas separating the declarators in a multiple declaration like int i, j;. See also How does the Comma Operator work?.

And then there's the "style" question of why it was written this way, or if it was a good idea to write it this way.

Macros in C work by textual replacement. They don't have to look like anything, they don't have to make sense, in general the only way to understand them is to look at what you get after expanding them. Here, whenever you write LCD_SELECT_CS1, what you get is

(PORTD |= (1<<3), PORTD &= ~(1<<2))

and if you can understand what (PORTD |= (1<<3), PORTD &= ~(1<<2)) does, you're done.

Normally, to avoid confusion, a macro ought to expand either to a single object or expression, or if it expands to a sequence of things, it ought to be a "function-like macro" that takes an argument list, more like it was a function. Since this LCD_SELECT_CS1 macro doesn't match either of those patterns, we find that it is confusing, and therefore poor style.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • The traditional idiom instead would be `#define foo() do { whatever; } while(0)`, permitting the macro invocation to resemble a function call, including producing a single statement that requires a semicolon termination. – Yann Vernier Sep 13 '19 at 20:55
0

This is what's happening:

  • PORTD |= (1<<3) does an inclusive OR of PORTD with Bit3 (1 left shifted 3 times). This should set the bit if it's not already set and not change any of the other bits in the port.
  • Next, the macro clears Bit2 of PORTD using PORTD &= ~(1<<2) where the ~(1<<2) acts as bit mask to always cause Bit2 to 0 since that bit will be set to 0 in the mask, while all other bits are set to 1. The macro returns the new value of Bit2 (always 0).

Updated: To correct the second point per the excellent observation of Antoine Mathys.

daShier
  • 2,056
  • 2
  • 8
  • 14