#include <stdio.h>
avr-libc
. Due to the nature of the underlying hardware, only a limited subset of standard IO is implemented. There is no actual file implementation available, so only device IO can be performed. Since there's no operating system, the application needs to provide enough details about their devices in order to make them usable by the standard IO facilities.
Due to space constraints, some functionality has not been implemented at all (like some of the printf
conversions that have been left out). Nevertheless, potential users of this implementation should be warned: the printf
and scanf
families of functions, although usually associated with presumably simple things like the famous "Hello, world!" program, are actually fairly complex which causes their inclusion to eat up a fair amount of code space. Also, they are not fast due to the nature of interpreting the format string at run-time. Whenever possible, resorting to the (sometimes non-standard) predetermined conversion facilities that are offered by avr-libc will usually cost much less in terms of speed and code size.
In order to allow programmers a code size vs. functionality tradeoff, the function vfprintf() which is the heart of the printf family can be selected in different flavours using linker options. See the documentation of vfprintf() for a detailed description. The same applies to vfscanf() and the scanf
family of functions.
The standard streams stdin
, stdout
, and stderr
are provided, but contrary to the C standard, since avr-libc has no knowledge about applicable devices, these streams are not already pre-initialized at application startup. Also, since there is no notion of "file" whatsoever to avr-libc, there is no function fopen()
that could be used to associate a stream to some device. (See note 1.) Instead, the function fdevopen()
is provided to associate a stream to a device, where the device needs to provide a function to send a character, to receive a character, or both. There is no differentiation between "text" and "binary" streams inside avr-libc. Character \n
is sent literally down to the device's put()
function. If the device requires a carriage return (\r
) character to be sent before the linefeed, its put()
routine must implement this (see note 2).
It should be noted that the automatic conversion of a newline character into a carriage return - newline sequence breaks binary transfers. If binary transfers are desired, no automatic conversion should be performed, but instead any string that aims to issue a CR-LF sequence must use "\r\n"
explicitly.
For convenience, the first call to fdevopen()
that opens a stream for reading will cause the resulting stream to be aliased to stdin
. Likewise, the first call to fdevopen()
that opens a stream for writing will cause the resulting stream to be aliased to both, stdout
, and stderr
. Thus, if the open was done with both, read and write intent, all three standard streams will be identical. Note that these aliases are indistinguishable from each other, thus calling fclose()
on such a stream will also effectively close all of its aliases (note 3).
All the printf
and scanf
family functions come in two flavours: the standard name, where the format string is expected to be in SRAM, as well as a version with the suffix "_P" where the format string is expected to reside in the flash ROM. The macro PSTR
(explained in Program Space String Utilities) becomes very handy for declaring these format strings.
fopen()
but since this would have required to parse a string, and to take all the information needed either out of this string, or out of an additional table that would need to be provided by the application, this approach was not taken.put()
for fdevopen()
that talks to a UART interface might look like this:int uart_putchar(char c) { if (c == '\n') uart_putchar('\r'); loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; }
printf()
instead of fprintf(mystream, ...)
saves typing work, but since avr-gcc needs to resort to pass all arguments of variadic functions on the stack (as opposed to passing them in registers for functions that take a fixed number of parameters), the ability to pass one parameter less by implying stdin
will also save some execution time.
Defines | |
#define | FILE struct __file |
#define | stdin (__iob[0]) |
#define | stdout (__iob[1]) |
#define | stderr (__iob[2]) |
#define | EOF (-1) |
#define | putc(__c, __stream) fputc(__c, __stream) |
#define | putchar(__c) fputc(__c, stdout) |
#define | getc(__stream) fgetc(__stream) |
#define | getchar() fgetc(stdin) |
Functions | |
int | fclose (FILE *__stream) |
int | vfprintf (FILE *__stream, const char *__fmt, va_list __ap) |
int | vfprintf_P (FILE *__stream, const char *__fmt, va_list __ap) |
int | fputc (int __c, FILE *__stream) |
int | printf (const char *__fmt,...) |
int | printf_P (const char *__fmt,...) |
int | sprintf (char *__s, const char *__fmt,...) |
int | sprintf_P (char *__s, const char *__fmt,...) |
int | snprintf (char *__s, size_t __n, const char *__fmt,...) |
int | snprintf_P (char *__s, size_t __n, const char *__fmt,...) |
int | vsprintf (char *__s, const char *__fmt, va_list ap) |
int | vsprintf_P (char *__s, const char *__fmt, va_list ap) |
int | vsnprintf (char *__s, size_t __n, const char *__fmt, va_list ap) |
int | vsnprintf_P (char *__s, size_t __n, const char *__fmt, va_list ap) |
int | fprintf (FILE *__stream, const char *__fmt,...) |
int | fprintf_P (FILE *__stream, const char *__fmt,...) |
int | fputs (const char *__str, FILE *__stream) |
int | fputs_P (const char *__str, FILE *__stream) |
int | puts (const char *__str) |
int | puts_P (const char *__str) |
size_t | fwrite (const void *__ptr, size_t __size, size_t __nmemb, FILE *__stream) |
int | fgetc (FILE *__stream) |
int | ungetc (int __c, FILE *__stream) |
char * | fgets (char *__str, int __size, FILE *__stream) |
char * | gets (char *__str) |
size_t | fread (void *__ptr, size_t __size, size_t __nmemb, FILE *__stream) |
void | clearerr (FILE *__stream) |
int | feof (FILE *__stream) |
int | ferror (FILE *__stream) |
int | vfscanf (FILE *__stream, const char *__fmt, va_list __ap) |
int | vfscanf_P (FILE *__stream, const char *__fmt, va_list __ap) |
int | fscanf (FILE *__stream, const char *__fmt,...) |
int | fscanf_P (FILE *__stream, const char *__fmt,...) |
int | scanf (const char *__fmt,...) |
int | scanf_P (const char *__fmt,...) |
int | sscanf (const char *__buf, const char *__fmt,...) |
int | sscanf_P (const char *__buf, const char *__fmt,...) |
FILE * | fdevopen (int(*put)(char), int(*get)(void), int opts __attribute__((unused))) |
|
|
|
|
|
The macro |
|
The macro |
|
The macro |
|
The macro |
|
Stream destined for error output. Unless specifically assigned, identical to
If |
|
Stream that will be used as an input stream by the simplified functions that don't take a
The first stream opened with read intent using |
|
Stream that will be used as an output stream by the simplified functions that don't take a
The first stream opened with write intent using |
|
Clear the error and end-of-file flags of |
|
This function closes It currently always returns 0 (for success). |
|
This function is a replacement for
It opens a stream for a device where the actual device implementation needs to be provided by the application. If successful, a pointer to the structure for the opened stream is returned. Reasons for a possible failure currently include that neither the
If the
If the If both functions are provided, the stream is opened with read and write intent.
The first stream opened with read intent is assigned to
The third parameter fdevopen() uses calloc() (und thus malloc()) in order to allocate the storage for the new stream. |
|
Test the end-of-file flag of
|
|
Test the error flag of |
|
The function |
|
Read at most
If an error was encountered, the function returns NULL and sets the error flag of |
|
The function |
|
Variant of |
|
The function |
|
Write the string pointed to by Returns 0 on success and EOF on error. |
|
Variant of fputs() where |
|
Read
Returns the number of objects successfully read, i. e. |
|
The function See vfscanf() for details. |
|
Variant of fscanf() using a |
|
Write
Returns the number of objects successfully written, i. e. |
|
Similar to fgets() except that it will operate on stream |
|
The function |
|
Variant of |
|
Write the string pointed to by |
|
Variant of puts() where |
|
The function See vfscanf() for details. |
|
Variant of scanf() where |
|
Like
Returns the number of characters that would have been written to |
|
Variant of |
|
Variant of |
|
Variant of |
|
The function See vfscanf() for details. |
|
Variant of sscanf() using a |
|
The ungetc() function pushes the character Currently, only a single character can be pushed back onto the stream.
The ungetc() function returns the character pushed back after the conversion, or |
|
The format string is composed of zero or more directives: ordinary characters (not
The conversion specifiers and their meanings are:
In no case does a non-existent or small field width cause truncation of a numeric field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result. Since the full implementation of all the mentioned features becomes fairly large, three different flavours of vfprintf() can be selected using linker options. The default vfprintf() implements all the mentioned functionality except floating point conversions. A minimized version of vfprintf() is available that only implements the very basic integer and string conversion facilities, but none of the additional options that can be specified using conversion flags (these flags are parsed correctly from the format specification, but then simply ignored). This version can be requested using the following compiler options:
-Wl,-u,vfprintf -lprintf_min If the full functionality including the floating point conversions is required, the following options should be used:
-Wl,-u,vfprintf -lprintf_flt -lm
|
|
Variant of |
|
Formatted input. This function is the heart of the
Characters are read from
The format string Most conversions skip leading white space before starting the actual conversion. Conversions are introduced with the character . Possible options can follow the :
In addition, a maximal field width may be specified as a nonzero positive decimal integer, which will restrict the conversion to at most this many characters from the input stream. This field width is limited to at most 127 characters which is also the default value (except for the The following conversion flags are supported:
These functions return the number of input items assigned, which can be fewer than provided for, or even zero, in the event of a matching failure. Zero indicates that, while there was input available, no conversions were assigned; typically this is due to an invalid input character, such as an alphabetic character for a
By default, all the conversions described above are available except the floating-point conversions, and the
-Wl,-u,vfscanf -lscanf_flt -lm
A third version is available for environments that are tight on space. This version is provided in the library
-Wl,-u,vfscanf -lscanf_min -lm
In addition to the restrictions of the standard version, this version implements no field width specification, no conversion assignment suppression flag ( |
|
Variant of vfscanf() using a |
|
Like
Returns the number of characters that would have been written to |
|
Variant of |
|
Like |
|
Variant of |