Hello, This code is from "Test Your C Skills" Book. In the book they have mentioned that this code won't work, and thats true. But I am not able to understand, why its not working. Please explain why it gives error.

#include<stdio.h>
#define SWAP(a,b,c) c t;t=a;a=b;b=t;

int main()
{
    float x=10,y=20;
    float *p,*q;
    p=&x;
    q=&y;
    SWAP(p,q,float*);
    printf("%f %f",x,y);

    return 0;
}

It works fine; the pointers are swapped in value. What error do you get?

Edited 3 Years Ago by Moschops

Thanks for the reply Moschops.
Just now I tried this code on Linux(Opensuse), Its working successfully.

Earlier I tried this code on windows (IDE = visual studio), It was giving following errors:
: error C2143: syntax error : missing ';' before 'type'
: error C2065: 't' : undeclared identifier
: warning C4047: '=' : 'int ' differs in levels of indirection from 'float *'
: warning C4047: '=' : 'float *' differs in levels of indirection from 'int '
Error executing cl.exe.

Let me start by saying I know next to nothing about C. However, line 2 doesn't look right. Shouldn't it be c=t;

#define SWAP(a,b,c) c=t;t=a;a=b;b=t;

No, it shouldn't. float* t; is a perfectly legal variable declaration in C - float* = t; is not.

Earlier I tried this code on windows (IDE = visual studio), It was giving following errors:

The problem is that in C89 you're only allowed to declare variables at the beginning of a block. No further variable declarations are allowed after the first non-declaration in a given block.

So this would be legal:

int main() {
    int x = 7;
    int y = 8;
    return 0;
}

But this would not:

int main() {
    int x;
    x = 7;
    int y = 8;
    return 0;
}

Because here line 4 is a declaration, but line 3 isn't. If you put the declaration of y in a new block, it's legal again:

int main() {
    int x;
    x = 7;
    {
        int y = 8;
        return 0;
    }
}

So to fix your code sample, you can either initialize p and q on line 7 and remove lines 8 and 9, so that the declaration of t is still at the beginning of the block - or you could add braces around the body of your macro, so that it creates its own block.

The latter is much preferable because it allows you to use the macro in the middle of a block - not just at the beginning - and it limits the scope of the t variable, so that you can use SWAP multiple times in the same scope and even in a scope where there's already a variable named t without running into a naming conflict. You'll only run into a problem if one of the variables you want to swap is named t - I don't think you can avoid that (other than renaming t to something less likely to cause a conflict, but of course that only reduces the risk - it doesn't eliminate it).

Redefine SWAP this way.
#define SWAP(a,b) float * t=a;a=b;b=t;

I'm not sure how you can pass implicit type to the define pre-processor. If anyone has any idea, I'd love to know.

By the way, you could also perform a XOR swap.

#define SWAP(a,b) a^=b;b^=a;a^=b;
#define SWAPPTRCONT(a,b) *a^=*b;*b^=*a;*a^=*b;

Edited 3 Years Ago by Unimportant

Hardcoding float* instead of passing it in as a parameter won't make the code compile in Visual Studio, nor will it fix any other problems the macro has. The only thing it will do is make the code less general.

By the way, you could also perform a XOR swap.

Neither pointers nor floats can be operands to ^, so neither of your macros will work with the OP's float pointers.

Edited 3 Years Ago by sepp2k

Thanks everyone for your helpful replies.
@sepp2k Thanks a lot to you. You explained thoroughly. Issue resolved.

This question has already been answered. Start a new discussion instead.