carl.hiass
carl.hiass

Reputation: 1784

Usage of macro vs function for the following utility

I would like to print a line break in C to help separate print statements for debugging. Here are two versions that I have now:

int main(void)
{
    repeat('-', 21);
    REPEAT('-', 21);
}

Function:

void repeat(const char value, const unsigned int count) {
    char vals[count+1];
    vals[count] = '\0';
    for (unsigned int i=0; i < count; i++)
        vals[i] = value;
    printf("%s\n", vals);
}

Macro:

#define REPEAT(value, count) \
    char vals[count+1]; \
    vals[count] = '\0'; \
    for (unsigned int i=0; i < count; i++) \
        vals[i] = value; \
    printf("%s\n", vals);

I am quite new to C and this is actually the first function-macro I've used, so my questions is which of the above approaches is more preferred? Why would one approach be better than the other? The 'function' approach seems a bit cleaner to me, but I see so many macros in other's code that it seems like any utility that can be made into a macro is often done so.

Upvotes: 0

Views: 48

Answers (2)

0___________
0___________

Reputation: 68004

  1. Use functions. Macros should be used as last "resort" when there is no other choice.
  2. Newer write the macros the way you did. Never end the macro with ';'

The correct version of the macro:

#define REPEAT(value, count) \
    do { char vals[(count)+1]; \
    vals[count] = '\0'; \
    for (unsigned int i=0; i < (count); i++) \
        vals[i] = value; \
    printf("%s\n", vals);} while(0)

What is wrong with your macro?

Example code

if (argc == 1) REPEAT('-', 32); 

will not compile at all https://godbolt.org/z/h39hr5.

Upvotes: 0

Eric Postpischil
Eric Postpischil

Reputation: 224146

Between the macro and the function, prefer the function. Use of macros should be limited, and problems with them include:

  • Declaring identifiers in macros can interfere with code in the calling scope, as it may hide a previous declaration and/or prevent using the macro more than once.
  • The macro uses its arguments more than once, which means that side effects will be evaluated more than once. For example, if n++ is passed for count, the replacement code generated by the macro will increment n more than once.

However, there is no great need for either a macro or a function here, and there is no need to create a string. To output a character repeatedly, merely output it repeatedly:

for (int i = 0; i < 21; ++i)
    putchar('-');
putchar('\n');

If that is to be done several times, it can be made into a function.

(If this were to be executed many many times and were a performance issue, it might be worthwhile to create a string that is kept around, either by defining the string in the source code or by creating it early in program execution, possibly in some initialization code. There are few circumstances in which this would actually be beneficial, as the code that inserts the string in an output stream (such as printf or fputs) still has to copy each character, and output to external devices may be much slower than the CPU can execute the loop above anyway.)

Upvotes: 1

Related Questions