1

When trying to use a block structure as the "replacement text" with a #define statement, e.g the below,

#define swap(t,x,y) { t _z;                     \
_z = x;                                     \
x = y;                                      \
y = _z;                }

Then I try to use it with:

printf( "%.2f %.2f\n", pow(a,b), pow( swap(int,a,b) ) );

But I get the following compiler error

    414.c:14:21: error: expected expression before ‘{’ token
 #define swap(t,x,y) { t _z;   \
                     ^
414.c:27:41: note: in expansion of macro ‘swap’
   printf( "%.2f %.2f\n", pow(a,b), pow( swap(int,a,b) ) );
                                         ^~~~

Is it not permissible to use block structures like this? What if I want to use a variable local to the macro?

The problem prompt specifically says to use block structures and the "C Answer Book" has this exact piece of code as the solution.

  • 2
    What is `pow( swap(int,a,b) )` supposed to mean in the first place? That code doesn't make any sense regardless of the macro. – Lundin Jan 14 '19 at 12:29
  • You could simply use `pow(b,a)`. Even if your example would work, you do not know if the swap is executed before or after the left `pow`. – mch Jan 14 '19 at 12:33
  • 1
    *"The problem prompt specifically says to use block structures and the "C Answer Book" has this exact piece of code as the solution."* Hmmm. Well, it's unfortunate they wouldn't have added a disclaimer that [what you are making is not an *expression*, but rather a *statement*.](https://stackoverflow.com/questions/27600153/explaining-the-difference-between-a-statement-and-an-expression-in-c) You can do some things with the [comma operator](https://en.cppreference.com/w/cpp/language/operator_other) that provide a bit of magic, but missing from that magic is being able to declare a variable. – HostileFork says dont trust SE Jan 14 '19 at 12:35
  • This *exact* piece of code? Apologies for the bluntness, but it means the books is either terrible, or you didn't pay enough attention to whatever details it provided. – StoryTeller - Unslander Monica Jan 14 '19 at 12:37
  • @StoryTeller Are you suggesting there are bad books about C? :-( Oh no. – HostileFork says dont trust SE Jan 14 '19 at 12:42
  • @HostileFork - I'm also willing to flat out come out and say that majority of them are ungood. – StoryTeller - Unslander Monica Jan 14 '19 at 12:44
  • The book does not claim that the macro can be used as an expression, nor does it contain any use of it. – molbdnilo Jan 14 '19 at 12:45
  • @Lundin it's the pow() function from math.h, and swap(t,x,y) is supposed to "interchange two arguments of type t" what's there not to understand? – Çınar Doruk Jan 14 '19 at 12:49
  • @ÇınarDoruk Yes, that's what `pow` and `swap` do separately. But putting them together like that doesn't make sense and it isn't clear what you think it's supposed to do. – interjay Jan 14 '19 at 12:51
  • @StoryTeller Yes. That exact piece. This book, page 96 https://www.amazon.com/Answer-Book-Solutions-Exercises-Programming/dp/0131096532 – Çınar Doruk Jan 14 '19 at 12:51
  • It contains or hints that `pow( swap(int,a,b) )` is valid in any way shape or form? Really? – StoryTeller - Unslander Monica Jan 14 '19 at 12:52
  • @ÇınarDoruk [pow() takes two arguments](https://en.cppreference.com/w/c/numeric/math/pow). You haven't made it clear why you expect a macro ending in "y = _z;" to evaluate to a pair of arguments; that would involve a bit of psychic powers of the compiler from what you have written. One thing to be very conscious of in learning a language is that it does what it does, not what you imagine that it does...so the sooner you get used to that the better. :-) – HostileFork says dont trust SE Jan 14 '19 at 12:53
  • I think "interchange two arguments of type t" is a bit of informal writing that means "interchange the values of two variables, passed as arguments, of type t". – molbdnilo Jan 14 '19 at 12:53
  • @interjay ooh now I get it. Thanks. – Çınar Doruk Jan 14 '19 at 12:58
  • @StoryTeller oh no that was just me( very erroneously) putting swap() in pow() to test and see if it works. The book just has the #define part. – Çınar Doruk Jan 14 '19 at 13:00
  • 1
    That's reassuring. Keep up the learning. A good lesson to take from this is that putting things in their own statements is usually less error prone. – StoryTeller - Unslander Monica Jan 14 '19 at 13:02
  • @ÇınarDoruk In case you aren't aware, a lot of C++ is about doing this kind of thing better; templates in C++ are far more powerful and expressive than preprocessor macros. (The preprocessor that does the `#define` substitutions knows nothing of the language, and abuses such as this are really generally a bad idea, that you only do as a last resort.) So don't get too attached to the preprocessor, this kind of trickery is largely frowned upon, you almost always should do it another way. – HostileFork says dont trust SE Jan 14 '19 at 13:04
  • 1
    Thanks so much everyone. Would've spent a lot of time not seeing why I was mistaken if not for you. – Çınar Doruk Jan 14 '19 at 13:09

2 Answers2

2

If the macro is expanded

printf( "%.2f %.2f\n", pow(a,b), pow( swap(int,a,b) ) );

becomes

printf( "%.2f %.2f\n", pow(a,b), pow( { int z; z=a; a=b; b=z} ) ) );

The { } is not valid as an expression. Also pow takes two parameters. You can rewrite it as

printf( "%.2f", pow(a,b));
swap(int,a,b);
printf( "%.2f\n", pow(a,b));
cup
  • 7,589
  • 4
  • 19
  • 42
0

The problem is that your macro is expanded to this:

{ int _z;
_z = a;
a = b;
b = _z; }

And soon your call becomes:

printf( "%.2f %.2f\n", pow(a,b), pow( { int _z; _z = a; a = b; b = _z; } ) );

Since pow requires 2 arguments and you're passing a block, it fails to compile.

Is it not permissible to use block structures like this?

Not as an argument to a function that expects 2 numeric arguments (double, int, or whatever).

What if I want to use a variable local to the macro?

The way you declared the local variable is correct.

jweyrich
  • 31,198
  • 5
  • 66
  • 97