Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fputc vs putc in C

Tags:

I was reading the C programming book by Kernighan and and came across putc and fputc. I didn't quite understand the difference between the two or when would one be used over the other. I found some posts on StackOverflow which dealt with this topic but it's still unclear.

As mentioned here (putc needs stdout, vs puts) :

  1. According to Kernighan's book putc is equivalent to fputc but putc could be implemented as a macro and putc may evaluate its stream argument more than once.

  2. The difference between putc and fputc is that by using putc, you risk running the macro version which is inherently unsafe because it may have to evaluate its stream argument more than once. This causes complications that most people aren't aware of and thus do not watch out for, so fputc is better to use. fputc's macro does not have this problem.

Questions:

  1. putc can be implemented as a macro but what is the problem doing same with fputc?

  2. The second statement mentions of some complications and safety issues. What are those?

  3. putc evaluates its argument more than once. So what are the advantages or disadvantages it poses compared to evaluating the argument.

like image 922
Vivek Rai Avatar asked Dec 23 '12 05:12

Vivek Rai


People also ask

What is the difference between Fputs and fputc?

fputc() writes the character c, cast to an unsigned char, to stream. fputs() writes the string s to stream, without its trailing '\0'.

What is the different between putc () puts () putchar () functions?

The putc() function converts c to unsigned char and then writes c to the output stream at the current position. The putchar() is equivalent to putc( c , stdout) . The putc() function can be defined as a macro so the argument can be evaluated multiple times.

How do you use fputc?

The syntax of the fputc() function is as follows: Syntax: int fputc(int ch, FILE *fp); The fputc() function is used to write a single character specified by the first argument to a text file pointed by the fp pointer. After writing a character to the text file, it increments the internal position pointer.


1 Answers

The issue with a macro implementation is that if any of the arguments have side effects, those side effects may be evaluated more than once, possibly leading to undefined behavior. Consider this toy example:

#define SQUARE(x) ((x) * (x))

Most of the time, this will function as expected, but if you pass in an expression such as f(), then the side effect of calling the function f() will happen twice, not once, since the preprocessor is just a text transformer which is ignorant of C:

int f()
{
    printf("f() was called\n");
    return 42;
}
...
int x = SQUARE(f());  // This calls f() twice!  It gets expanded to this:
// int x = (f() * f());

To put this in perspective, the putc function, if implemented as a macro, may evaluate its stream argument more than once. So, if that stream comes from a function:

FILE *get_file()
{
    // Potential side effects could happen here
    return some_file;
}
...
putc('A', get_file());

Then that could result in the function get_file() getting called more than once, with potentially unwanted side effects.

The solution, of course, is to just call a regular function like fputc() instead of putc(). Since it's not a macro, it doesn't have any potential problems with evaluating its arguments more than once. Macros can be dangerous sometimes, so use them with care.

like image 191
Adam Rosenfield Avatar answered Sep 20 '22 15:09

Adam Rosenfield