0

i am trying to understand macro in c. i had found this program as a question to extract the error obviously it need to swap the numbers using exclusive or (i can not also understand why using xor to swap)

#include <stdio.h>
#include <stdlib.h>
#define SWAP(a, b) { a ^= b; b ^= a; a ^= b;}
int main(void) {
int x = 10;
int y = 5;
int z = 4;
if (x < 0)
 SWAP(x, y);
else
 SWAP(x, z);
}

the compiler popped an error to include if before else. but obviously there is an if before else i want to understand the reason behind this.

Mai Ehab
  • 13
  • 7
  • 2
    Remove the `;` after the macro calls. Or add braces to the `if/else` blocks. – kaylum Aug 10 '22 at 01:28
  • Definitely add braces to the `if` and `else` blocks. Using braces routinely, even for single-statement blocks, protects you against a variety of oddities and potential mistakes. – John Bollinger Aug 10 '22 at 01:36
  • 1
    Also, if you are going to write a macro whose expansion itself contains a code block, then a widespread idiom is to structure it as a `do { ... } while (0)`. That would work for you without removing the semicolons, but you should still (also) use braces around the `if` and `else` bodies. – John Bollinger Aug 10 '22 at 01:40
  • 1
    https://en.wikipedia.org/wiki/XOR_swap_algorithm – Fe2O3 Aug 10 '22 at 01:40
  • 2
    Don't ever swap like this. It's **hugely** inefficient if it's not optimized out (count the store and bitwise operations compared to "load a in r1, load b in r2, store r2 in a, store r1 in b" of a sane swap with a temp value). And with signed integer values in C it risks undefined behavior. Signed integer overflow is undefined behavior in C, and the intermediate values could result in a value outside the range of a valid signed integer value - or signed integer overflow. – Andrew Henle Aug 10 '22 at 01:49
  • @Fe2O3 Note, thought, that the C example on that Wiki page risks undefined behavior. – Andrew Henle Aug 10 '22 at 01:50
  • See also [Why use apparently meaningless `do`/`while` and `if`/`else` in macros?](https://stackoverflow.com/q/154136/15168) – Jonathan Leffler Aug 10 '22 at 01:53
  • @AndrewHenle The C example would have been better wih `unsigned`, I agree. But, is "overflow" a concern with bitwise XOR? That'd be news to me... Thanks for catching that. – Fe2O3 Aug 10 '22 at 02:09

2 Answers2

0

The problem is the ; after SWAP(x, y).

Once the macro substitution is performed by the preprocessor, here's what the code looks like (with the ; moved to a separate line for illustrative purposes):

if (x < 0)
 { x ^= y; y ^= x; x ^= y;}
 ;
else
 { x ^= z; z ^= x; x ^= z;}
 ;

The block in { } after the if is valid, and technically so is it the ;, but it makes the else invalid syntax.

As the comments indicate, the best fix is to remove the ;, but also put the if/else blocks in braces, like this:

if (x < 0) {
 SWAP(x, y)
} else {
 SWAP(x, z)
}
sj95126
  • 6,520
  • 2
  • 15
  • 34
0

The issue is caused by a semicolon after closing braces:

{ ... };
       ^ here

The C grammar does not allow that. The solution is using do {} while (0) trick. Which a dummy loop that is always executed once and it allows a semicolon after it.

Just define your macro as:

#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b;} while (0)
tstanisl
  • 13,520
  • 2
  • 25
  • 40