In AVR-libc page 143 the implementation of the function uart_putchar() is typical as the following:

#include <stdio.h>

static int uart_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

static int
uart_putchar(char c, FILE *stream)
if (c == '\n')
  uart_putchar('\r', stream);
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
  stdout = &mystdout;
  printf("Hello, world!\n");
  return 0;

I know that we can redirect a specific stream to a stdout or stdin using fdevopen().

But is not the variable stream is not used in this function? Why is there such a variable that not used by the function? Is that because the fdevopen() pointers to functions parameters?


2 Answers 2


You are not specifically creating a UART stream. You are creating a generic stream that happens to go to the UART.

Many times streams can go to different places. As the variable type FILE suggests it's commonly to a file - such as on an SD card. In these situations the FILE parameter is essential for the function to know exactly where the data is to go to.

For the UART it is irrelevant since there is only one place it can go - the UART.

The functions that interact with whatever you implement expect a certain prototype and pass certain parameters. Whether you use those parameters or not you have to accept them and have them in your function prototype - otherwise you just can't compile your code (you have a mismatch in the function pointer definitions).

  • 1
    \$\begingroup\$ Shouldn't the compiler throw a warning at compile time because of that unused variable? \$\endgroup\$
    – NAND
    Commented Feb 19, 2022 at 13:04
  • 1
    \$\begingroup\$ @NAND It is used in this case - it's passed to the recursive line feed / cr call. Plus not all compilers have it turned on by default. \$\endgroup\$
    – Majenko
    Commented Feb 19, 2022 at 13:24

Why is there such a variable that not used by the function?

The first parameter of fdevopen takes a parameter of type

int (*)(char, FILE*)

which is a pointer to a function that returns int and which takes two arguments: One of type char and then one of type FILE*.

Consequently, when providing (the address of) a putter function to fdevopen, that function must have the same signature, even if some argument is unused. Same applies to the first argument of FDEV_SETUP_STREAM, which is used to initialize some FILE object, and where the respective component also has that type.

Strictly speaking, parameter stream is used in the example because it is passed down to a self-call of uart_putchar. If it was really unused, you could do the following:

  • C++: Omit the parameter name like in int uart_putchar (char c, FILE*) { ... }
  • C++17, C23: Mark the parameter with attribute [[maybe_unused]].
  • GNU-C, GNU-C++: Mark the parameter with __attribute__((__unused__)).
  • Add a line (void) stream;.

All these means tell a reader that the parameter is unused, and they tell the compiler that it's fine that the parameter is unused so the compiler will not throw a diagnostic at you.


Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.