Macros

Macros

Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
So, what exactly is the point of macros inside programs? Why wouldn't you just write a separate function? It seems to be the same, except that macros can't be made (or are harder to make) for more complicated things.

To avoid confusion, this is what I'm talking about:

C code
#define max(A, B) ((A) > (B)) ? (A) : (B)


as opposed to

C code
max (a, b)
int a, b;
{
return ((a > b) ? a : b);
}




EDIT: Also, how would you write a macro swap(x, y) that swaps the values of x and y, since you can't define any new variables in the macro? (You need a temporary variable to hold the value of one of those two variables.)



EDIT 2: Task: Write a macro strcopy(x, y) that copies the content of string y into x.
My solution looks like this:

C code
#define strcopy(x, y) while (x++ = y++);

This however requires that x and y are defined as pointers, not
strings. So my program looks like this:

C code
int main()
{
char s[MAXSTRING], t[MAXSTRING];
char *ps = s, *pt = t;

while ((*pt++ = getchar()) != '\n');
*pt = '\0';

strcopy (*ps, *pt);
printf ("%s\n", s);
return 0;
}

Is there a way to write this macro so it can look like this:

C code
int main()
{
char s[MAXSTRING], t[MAXSTRING];
char *pt = t;

while ((*pt++ = getchar()) != '\n');
*pt = '\0';

strcopy (s, t);
printf ("%s\n", s);
return 0;
}
...and that's the bottom line because Mate de Vita said so.
 
 
 
2011 Mar 16 at 13:43 PDT — Ed. 2011 Mar 16 at 14:46 PDT
SuperJer
Websiteman

2005 Mar 20 • 6629
If you can write something as a function, then do. Macros are overused, I think.

Macros are hard to debug so they're pretty evil.

But sometimes you need them anyway.

In your MAX(a,b) example, the macro is better because it will work for any type that can be compared with the > operator.

Another example is error logging. You can use __FILE__ and __LINE__ in a macro, for instance. Here's my assert macro from SPARToR:

c code

#define assert(expr) { if(!(expr)) SJC_Write( "%s(%d) Assert failed! %s", __FILE__, __LINE__, #expr ); }


It evaluates an expression, and if it is false, it will print the expression and the filename and line number. You can't do that with a function.
 
 
 
2011 Mar 16 at 14:10 PDT — Ed. 2011 Mar 16 at 14:44 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
And should superjer not want asserts he could, for example, change the assert macro to evaluate to nothing, thus completely getting rid of the code.

He's also right in that macros can be used for evil purposes. But then it becomes funny, right?
 
 
 
2011 Mar 16 at 14:16 PDT
SuperJer
Websiteman

2005 Mar 20 • 6629
swap(x,y)

You can actually define a new variable in a macro. Just make sure it goes out of scope at the end of the macro.

c code
#define swap(x,y) { int temp = x; x = y; y = temp; }


That will only work for ints though.

I think I can make it work for anything like this:

c code
#define swap(x,y) { \
char *temp = malloc(sizeof (x)); \
memcpy(temp,&(x),sizeof (x)); \
memcpy(&(x),&(y),sizeof (x)); \
memcpy(&(y),temp,sizeof (x)); \
free(temp); \
}


This is a bit unsafe. If x and y are different sizes, there will be problems.

You could have the macro check that sizeof (x) == sizeof (y).
 
 
 
2011 Mar 16 at 14:21 PDT — Ed. 2011 Mar 16 at 14:25 PDT
SuperJer
Websiteman

2005 Mar 20 • 6629
strcopy(x,y)

I think your macro is wrong. You're failing to dereference the pointers. This:

c code
#define strcopy(x, y) while (x++ = y++);


should probably be this:

c code
#define strcopy(x, y) while (*x++ = *y++);


The other problem is that your ++s are modifying the pointers in place, which isn't a cool thing for the macro to do at all. You should probably do this instead:

c code
#define strcopy(x, y) { \
char *X = (x); \
char *Y = (y); \
while (*X++ = *Y++); \
}


With this macro you can use pointers or "strings" (really "arrays") and it should work, because it makes the pointers itself.
 
 
 
2011 Mar 16 at 14:38 PDT — Ed. 2011 Mar 16 at 14:52 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
superjer said:
c code

#define assert(expr) { if(!(expr)) SJC_Write( "%s(%d) Assert failed! %s", __FILE__, __LINE__, #expr ); }


It evaluates an expression, and if it is false, it will print the expression and the filename and line number. You can't do that with a function.

Can you give me a simple example of how this is used in the actual program? What kind of an expression are we talking about here?
Also what's that #expr?


superjer said:
You can actually define a new variable in a macro. Just make sure it goes out of scope at the end of the macro.

Oh, OK. That does make macros a bit more useful then. I thought defining a macro simply replaced all the occurrences of the macro's name in the file with whatever the macro was defined as (kind of like #define BLAH 2000 replaces all BLAHs in the file with 2000, except that with a macro the arguments inside the macro would be changed properly), and afaik you can't define variables in loops or statements.


Also, can you define a macro as #define macro (x, y) blah blah or will the space between the macro's name and the arguments (or whatever they're called in a macro) cause problems?
...and that's the bottom line because Mate de Vita said so.
 
 
 
2011 Mar 17 at 09:33 PDT — Ed. 2011 Mar 17 at 09:34 PDT
SuperJer
Websiteman

2005 Mar 20 • 6629
Mate de Vita said:
Can you give me a simple example of how this is used in the actual program? What kind of an expression are we talking about here?
Also what's that #expr?


code
// player should NEVER be NULL here!
assert( player != NULL );


The # in #expr is the stringify operator. It converts expr into a string literal in the precompiler. It's very handy.

Mate de Vita said:
Oh, OK. That does make macros a bit more useful then. I thought defining a macro simply replaced all the occurrences of the macro's name in the file with whatever the macro was defined as (kind of like #define BLAH 2000 replaces all BLAHs in the file with 2000, except that with a macro the arguments inside the macro would be changed properly), and afaik you can't define variables in loops or statements.


That pretty much is what a macro is. Just text replacement. Well, plus substitution, stringification and token-pasting.

Unless you're using a very old (10+ years) C standard, you can declare variables (almost) anywhere you want.

Mate de Vita said:
Also, can you define a macro as #define macro (x, y) blah blah or will the space between the macro's name and the arguments (or whatever they're called in a macro) cause problems?


You can't have the space. Everything after the space is part of the definition.
 
 
 
2011 Mar 17 at 14:07 PDT — Ed. 2011 Mar 17 at 14:08 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
superjer said:
Unless you're using a very old (10+ years) C standard, you can declare variables (almost) anywhere you want.

So then you can do this in a program:
C code
int n = 0;

while (expr) n++;

char line[n];


If so, is this ever a bad idea for some reason? Or is there some other reason there's no mention of it anywhere in this book (it being old for example)?
...and that's the bottom line because Mate de Vita said so.
 
 
 
2011 Apr 7 at 09:28 PDT — Ed. 2011 Apr 7 at 09:31 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
 
 
 
2011 Apr 7 at 12:22 PDT
Mate de Vita
Kelli

2008 Oct 4 • 2453
159 ₧
Actually I meant you can define the array size with a variable, the value of which is determined in the program itself somehow.
...and that's the bottom line because Mate de Vita said so.
 
 
 
2011 Apr 7 at 13:05 PDT
Down Rodeo
Cap'n Moth of the Firehouse

Find the Hole II Participation Medal
2007 Oct 19 • 5486
57,583 ₧
Ummm... I don't think so. (Sorry for misunderstanding). Unless I have it horribly wrong, which is entirely possible, it is only in Java that you can dynamically allocate arrays. If you're in C you have to request a section of memory, pointers, herp derp.
 
 
 
2011 Apr 7 at 14:13 PDT
SuperJer
Websiteman

2005 Mar 20 • 6629
Since C99 (twelve years ago!) you can allocate arrays dynamically like that.

It is not always a good idea for 2 reasons:

1) If you want your code to compile with Visual Studio it won't. Microsoft will not support C99.

2) Allocating a var this way puts it on the stack. You don't want to just cram a ton of stuff onto the stack. At least think about it.

For small allocations that you only need locally, it's way more convenient/safe than malloc. At least in my experience, though, I don't end up using it that often. I just don't need it or malloc for most things.
 
 
 
2011 Apr 7 at 18:37 PDT — Ed. 2011 Apr 7 at 18:39 PDT
Page [1]