InsaneCoder
InsaneCoder

Reputation: 8268

Unexpected behaviour of macros in C

How can both the following codes execute (The codes are same except the semicolon in second line)

This code is expected to execute and does so as well.

#include<stdio.h>
#define SWAP(a, b) int t; t=a, a=b, b=t  //note here is no semi-colon at the end
int main()
{
    int a=10, b=12;
    SWAP(a, b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

But the following is not expected to run as SWAP(a, b) will be replaced by int t; t=a, a=b, b=t;;.So two semi-colons should produce error!!!

#include<stdio.h>
#define SWAP(a, b) int t; t=a, a=b, b=t;  //note the semi-colon here
int main()
{
    int a=10, b=12;
    SWAP(a, b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

Upvotes: 0

Views: 117

Answers (4)

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

Extra semicolons in local scope will never produce an error in C (after C99) if used as in your macro. They simply introduce an empty statement. Where did you get the idea that it should be an error? One can concoct an example that would trigger, say, an "orphaned else" error because of an extra semicolon, but your macro is not usable under if anyway (see below).

In C89/90 it was possible to trigger an error through an inadvertently placed extra semicolon after a declaration, because in C89/90 it was illegal to mix declarations and statements. For example

int a, b;;  /* <- A declaration followed by an empty statement */
int c;      /* <- ERROR: Illegal declaration after a statement */

But in C99 it is not a problem, since declarations and statements can be mixed. Your SWAP is obviously implemented for C99 so this issue does not immediately apply though.

It is worth noting that such implementation of SWAP is pretty poor and quite dangerous. It might lead to unexpected, dangerous and completely meaningless behavior in contexts like

if (/* whatever */)
  SWAP(a, b);

Better follow the do/while(0) idiom and do something like

#define SWAP(a, b) do { int t; t=a, a=b, b=t; } while (0)

Note - no semicolon at the end.

Upvotes: 4

P0W
P0W

Reputation: 47794

After using

gcc -E file_name.c you'll get for second code :-

int t; t=a, a=b, b=t;;

which is a valid

and equivalent to

int t; t=a, a=b, b=t;

; // null statement does nothing

Upvotes: 2

Joni
Joni

Reputation: 111239

A semi colon on its own is an "empty statement," a statement that does nothing.

It is sometimes useful, but most of the time it's an error. For example this if-statement does not have the intended effect:

if (x == y);
{
    z=1;
}

Despite this fact, it's a perfectly valid part of the C language.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 753675

The stray semi-colon becomes a null statement which is perfectly legitimate in C.

You could prove this by adding a line with a dozen semi-colons to your code.

Separately, your macro would be better written as:

#define SWAP(a, b) do { int t = a; a = b; b = t; } while (0)

This works better if you try to do two different swaps in a single block of code.

Upvotes: 7

Related Questions