0

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.

3
  • 3
    (a) Between the two, use the function. Macros should be very limited, and declaring new identifiers in macros can cause problems. For one thing, it would prevent using the macro twice in the same scope. (b) Do not use either. To output a character repeatedly, just use putchar repeatedly; do not create a string for it. Except, if the same sequence is going to be printed repeatedly, it might make sense to create a static array for it. Commented Jan 17, 2021 at 22:30
  • @EricPostpischil thanks, would you want to expand your comment into an answer and I can accept it. For example, why do you suggest using putchar instead of a local array to print, etc? Commented Jan 17, 2021 at 22:32
  • @carl.hiass Also, the usual macro gotchas like int n = 3; REPEAT('x', n++);. Commented Jan 17, 2021 at 23:14

2 Answers 2

1

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.)

Sign up to request clarification or add additional context in comments.

Comments

0
  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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.