C - Scanf with only read/write [duplicate] - c

How can I write (if it's possible at all...) a function which takes an unknown number of parameters in C99 (the return type is constant)?

Yes you can do it in C using what are referred to as Variadic Functions.
The standard printf() and scanf() functions do this, for example.
Put the ellipsis (three dots) as the last parameter where you want the 'variable number of parameters to be.
To access the parameters include the <stdarg.h> header:
#include <stdarg.h>
And then you have a special type va_list which gives you the list of arguments passed, and you can use the va_start, va_arg and va_end macros to iterate through the list of arguments.
For example:
#include <stdarg.h>
int myfunc(int count, ...)
{
va_list list;
int j = 0;
va_start(list, count);
for(j=0; j<count; j++)
{
printf("%d", va_arg(list, int));
}
va_end(list);
return count;
}
Example call:
myfunc(4, -9, 12, 43, 217);
A full example can be found at Wikipedia.
The count parameter in the example tells the called function how many arguments are passed. The printf() and scanf() find that out via the format string, but a simple count argument can do it too. Sometimes, code uses a sentinel value, such as a negative integer or a null pointer (see
execl()
for example).

Related

How can I add all the elements with a function with variable parameters in C? [duplicate]

How can I write (if it's possible at all...) a function which takes an unknown number of parameters in C99 (the return type is constant)?
Yes you can do it in C using what are referred to as Variadic Functions.
The standard printf() and scanf() functions do this, for example.
Put the ellipsis (three dots) as the last parameter where you want the 'variable number of parameters to be.
To access the parameters include the <stdarg.h> header:
#include <stdarg.h>
And then you have a special type va_list which gives you the list of arguments passed, and you can use the va_start, va_arg and va_end macros to iterate through the list of arguments.
For example:
#include <stdarg.h>
int myfunc(int count, ...)
{
va_list list;
int j = 0;
va_start(list, count);
for(j=0; j<count; j++)
{
printf("%d", va_arg(list, int));
}
va_end(list);
return count;
}
Example call:
myfunc(4, -9, 12, 43, 217);
A full example can be found at Wikipedia.
The count parameter in the example tells the called function how many arguments are passed. The printf() and scanf() find that out via the format string, but a simple count argument can do it too. Sometimes, code uses a sentinel value, such as a negative integer or a null pointer (see
execl()
for example).

In C, how to pass a variable number of arguments (say, 50+) to a function which va_start() understands prior to calling vsnprintf()?

Question
Is there a way to pass many arguments to MyPrint() below using some kind of array containing a list of pointers to strings that va_start() understands before calling vsnprintf()?
Example of a format string specifier. It would be nice to create an array of the corresponding values and pass that to MyPrint() rather than individually passing each argument. I don't know if it's possible for va_start() to understand it. :(
"[0x%llX][%u] %s --- A=%llu (0x%llX) B=%llu (0x%llX) C=%llu (0x%llX) X=%llu (0x%llX) Y=%llu (0x%llX) Z=%llu (0x%llX)"
Details
MyPrint() calls vsnprintf() which prints a formatted list of arguments to a character array. The declaration for vsnprintf() is shown below:
int vsnprintf(char *arr, size_t len, const wchar_t *format, va_list args);
Parameters
arr: Pointer to the character array where output is to be printed
len: Maximum number of characters that can be written to the array
format: Format in which the output will be printed
args: Pointer to the list of arguments to be printed
Demo
#include <stdio.h>
#include <stdarg.h>
int MyPrint(char* buffer, int bufferSize, const char *format, ...)
{
int len = 0;
va_list arguments;
va_start(arguments, format);
len = vsnprintf(buffer, bufferSize, format, arguments);
va_end(arguments);
return len;
}
int main()
{
char buffer[256];
MyPrint(buffer, 256, "%s %s","Hello","World");
printf("%s",buffer);
return 0;
}
Is there a way to pass many arguments to MyPrint() below using some kind of array containing a list of pointers to strings that va_start() understands before calling vsnprintf()?
The only defined ways to initialize a va_list, such as vsnprintf() requires as a parameter, are
via the va_start() macro, operating in the context of a variadic function to form a va_list from the function's variadic arguments, and
via the va_copy() macro, to make a copy of another va_list.
There is no mechanism in standard C to form a va_list from the elements of an array, except by passing them all, individually, to a variadic function.
Variadic functions are about coding flexibility, not data flexibility. If you want a function that handles arrays of data, then write a (non-variadic) one that does so.
Whenever you consider writing your own varargs function, smack yourself in the head and repeat the mantra: "varargs is not the answer". Only if you still have varargs in your head after a few iterations of that should you should consider actually investigating that option.

How to use formatting strings in user-defined functions?

I want to write a function to print characters on an LCD in a similar way that printf/sprintf does using formatting strings.
You may use sprintf function to format the strings and print to LCD.
char buffer[50];
int a = 10, b = 20, c;
c = a + b;
sprintf(buffer, "Sum of %d and %d is %d", a, b, c);
Now the buffer will have the formatted strings
You could write a variadic function and pass the parameters on to vsnprintf():
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
void display(int foo, int bar, char const *format, ...)
{
va_list arglist;
va_start(arglist, format);
int length = vsnprintf(NULL, 0, format, arglist);
char *buffer = malloc(length * sizeof *buffer);
vsnprintf(buffer, length, format, arglist);
va_end(arglist);
puts(buffer);
free(buffer);
}
int main(void)
{
display(42, 13, "%s %d %f", "Hello", 99, 100.13);
}
This answer takes the best parts of all of the other answers and puts them into one. I consider it to be the best way to do this given all factors, and will explain in more detail after presenting the example.
Summary:
Here's a full example, including with basic error checking in the function. Here I create a printf-like function called lcd_printf(), which works exactly like printf(). It uses vsnprintf() to store a formatted string into a statically-allocated buffer. You can then send this buffer to the LCD display at the location indicated by my comment.
Example Code:
lcd_print.h:
// For info on the gcc "format" attribute, read here under the section titled
// "format (archetype, string-index, first-to-check)":
// https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Common-Function-Attributes.html#Common-Function-Attributes.
int lcd_printf(const char * format, ...) __attribute__((format(printf, 1, 2)));
lcd_print.c:
#include "lcd_print.h"
#include <stdarg.h> // for variable args: va_list
#include <stdio.h> // for vsnprintf()
#include <limits.h> // for INT_MIN
// `printf`-like function to print to the LCD display.
// Returns the number of chars printed, or a negative number in the event of an error.
// Error Return codes:
// 1. INT_MIN if vsnprintf encoding error, OR
// 2. negative of the number of chars it *would have printed* had the buffer been large enough (ie: buffer would
// have needed to be the absolute value of this size + 1 for null terminator)
int lcd_printf(const char * format, ...)
{
int return_code;
// Formatted string buffer: make as long as you need it to be to hold the longest string you'd ever want
// to print + null terminator
char formatted_str[128];
va_list arglist;
va_start(arglist, format);
// Produce the formatted string; see vsnprintf documentation: http://www.cplusplus.com/reference/cstdio/vsnprintf/
int num_chars_to_print = vsnprintf(formatted_str, sizeof(formatted_str), format, arglist);
va_end(arglist);
if (num_chars_to_print < 0)
{
// Encoding error
return_code = INT_MIN;
return return_code; // exit early
}
else if (num_chars_to_print >= sizeof(formatted_str))
{
// formatted_str buffer not long enough
return_code = -num_chars_to_print;
// Do NOT return here; rather, continue and print what we can
}
else
{
// No error
return_code = num_chars_to_print;
}
// Now do whatever is required to send the formatted_str buffer to the LCD display here.
return return_code;
}
main.c:
#include "lcd_print.h"
int main(void)
{
int num1 = 7;
int num2 = -1000;
unsigned int num3 = 0x812A;
lcd_printf("my 3 numbers are %i, %i, 0x%4X\n", num1, num2, num3);
return 0;
}
Explanation & comparison to alternate approaches:
#Harikrishnan points out you should use sprintf(). This is on the right track, and is a valid, but less versatile and complete approach. Creating a new variadic function which uses vsnprintf(), as #Swordfish and I have done, is better.
#Swordfish does a fantastic demonstration of the proper usage of vsnprintf() in order to create your own printf()-like variadic function. His example (aside from lacking error handling) is the perfect template for a custom printf()-like implementation which relies on dynamic memory allocation. His first call to vsnprintf(), with a NULL destination buffer, does nothing more than determine how many bytes he needs to allocate for the formatted string (this is an ingenious and commonly-used trick for this application), and his second call to vsnprintf() actually creates the formatted string. For non-real-time applications which also have large amounts of RAM (ex: PC applications) this is the perfect approach. However, for microcontrollers I strongly recommend against it because:
It is non-deterministic. Calling free() can take different (and indeterminable before-hand) amounts of time to complete each time you call it. This is because the heap memory becomes fragmented over time. This means this approach is not good for real-time systems.
For more information about various heap implementations for malloc() and free(), review the 5 heap implementations, for example, described by FreeRTOS here: https://www.freertos.org/a00111.html. Search this page for "deterministic".
It is unbounded. It will attempt to malloc() ANY amount of memory required for the formatted string. This is bad, as it is more prone to stack-overflow. On safety-critical microcontroller-based systems, stack overflow needs to be strongly guarded against. A preferred approach is to use statically-allocated memory like I have done, with a fixed maximum size.
Additionally, it is lacking the GCC "format" attribute, which is a nice touch (more on this below).
#P__J__ mentions the GCC "format" attribute. My example uses this as well.
If using the GCC compiler, or any other compiler which has something similar, this is highly recommended to add to any custom printf()-like function you make.
The GCC documentation, under the section called format (archetype, string-index, first-to-check), states:
The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments that should be type-checked against a format string.
In other words, it provides extra protections and checks to your custom printf()-like function at compile time. This is good.
For our case, simply use printf as the archetype, and a number for the string-index and first-to-check parameters.
The parameter string-index specifies which argument is the format string argument (starting from 1), while first-to-check is the number of the first argument to check against the format string.
Since non-static C++ methods have an implicit this argument, the arguments of such methods should be counted from two, not one, when giving values for string-index and first-to-check.
In other words, here are some valid example usages for this attribute applied to printf()-like function prototypes:
In C:
int lcd_printf(const char * format, ...) __attribute__((format(printf, 1, 2))); // 1 is the format-string index (1-based), and 2 is the variadic argument (`...`) index (1-based)
int lcd_printf(my_type my_var, const char * format, ...) __attribute__((format(printf, 2, 3))); // 2 is the format-string index (1-based), and 3 is the variadic argument (`...`) index (1-based)
int lcd_printf(my_type my_var, my_type my_var2, const char * format, my_type my_var3, ...) __attribute__((format(printf, 3, 5))); // 3 is the format-string index (1-based), and 5 is the variadic argument (`...`) index (1-based)
In C++:
int lcd_printf(const char * format, ...) __attribute__((format(printf, 2, 3))); // 2 is the format-string index (2-based), and 3 is the variadic argument (`...`) index (2-based)
int lcd_printf(my_type my_var, const char * format, ...) __attribute__((format(printf, 3, 4))); // 3 is the format-string index (2-based), and 4 is the variadic argument (`...`) index (2-based)
int lcd_printf(my_type my_var, my_type my_var2, const char * format, my_type my_var3, ...) __attribute__((format(printf, 4, 6))); // 4 is the format-string index (2-based), and 6 is the variadic argument (`...`) index (2-based)
Read more in my other answer here: How should I properly use __attribute__ ((format (printf, x, y))) inside a class method in C++?.
So, putting everything above together, you get the ideal solution for microcontrollers, which I've presented above.
as most commnly used arm compiler is gcc I will only focus on this one. The compiler can check the format & the prameters same as printf does
__attribute__ ((format (printf...
From the gcc documentation
format (archetype, string-index, first-to-check)
The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be
type-checked against a format string. For example, the declaration:
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument
my_format.
The parameter archetype determines how the format string is interpreted, and should be printf, scanf, strftime or strfmon. (You
can also use printf, scanf, strftime or strfmon.) The
parameter string-index specifies which argument is the format string
argument (starting from 1), while first-to-check is the number of the
first argument to check against the format string. For functions where
the arguments are not available to be checked (such as vprintf),
specify the third parameter as zero. In this case the compiler only
checks the format string for consistency. For strftime formats, the
third parameter is required to be zero.
In the example above, the format string (my_format) is the second argument of the function my_print, and the arguments to check start
with the third argument, so the correct parameters for the format
attribute are 2 and 3.
The format attribute allows you to identify your own functions which take format strings as arguments, so that GCC can check the
calls to these functions for errors. The compiler always (unless
-ffreestanding is used) checks formats for the standard library functions printf, fprintf, sprintf, scanf, fscanf, sscanf, strftime,
vprintf, vfprintf and vsprintf whenever such warnings are requested
(using -Wformat), so there is no need to modify the header file
stdio.h. In C99 mode, the functions snprintf, vsnprintf, vscanf,
vfscanf and vsscanf are also checked. Except in strictly conforming C
standard modes, the X/Open function strfmon is also checked as are
printf_unlocked and fprintf_unlocked. See Options Controlling C
Dialect. format_arg (string-index)
The format_arg attribute specifies that a function takes a format string for a printf, scanf, strftime or strfmon style function and
modifies it (for example, to translate it into another language), so
the result can be passed to a printf, scanf, strftime or strfmon style
function (with the remaining arguments to the format function the same
as they would have been for the unmodified string). For example, the
declaration:
extern char *
my_dgettext (char *my_domain, const char *my_format)
__attribute__ ((format_arg (2)));
causes the compiler to check the arguments in calls to a printf, scanf, strftime or strfmon type function, whose format string argument
is a call to the my_dgettext function, for consistency with the format
string argument my_format. If the format_arg attribute had not been
specified, all the compiler could tell in such calls to format
functions would be that the format string argument is not constant;
this would generate a warning when -Wformat-nonliteral is used, but
the calls could not be checked without the attribute.

va_arg always runs 4 times

I am learning stdarg.h in c i am trying to print all arguments passed to function without knowing how many arguments are there but yet i have not come up with solution, during this this happened, no matter what i pass to strtest.
It always print 0. 1. 2. 3.
void strtest(char *fmt, ...){
va_list argp;
int i = 0;
va_start(argp, fmt);
while(va_arg(argp, char*))
printf("%d\t", i++ );
va_end(argp);
}
int main(int argc, char *argv[]){
strtest("s");
printf("\n");
return 0;
}
There's no standard mechanism that will tell you the number of arguments passed to a varargs function. Functions like printf() work because they can determine the number of arguments by examining the format string.
Here is an example showing one way to pass an unknown number of arguments.
#include <stdio.h>
#include <stdarg.h>
void print (char *first, ...)
{
va_list argptr;
char *next;
va_start (argptr, first);
next = first;
while (next) {
printf ("%s\n", next);
next = va_arg(argptr, char*);
}
va_end (argptr);
}
int main(void)
{
print("hello","world", NULL); // NULL as sentinel
return 0;
}
Program output
hello
world
Perhaps you can adapt this to your needs using int arguments.
This is the definition of stdarg.h in the ISO 9899 WG14 n1256
The header <stdarg.h> declares a type and defines four macros, for advancing
through a list of arguments whose number and types are not known to the called function
when it is translated
You have to pass the number of arguments, and possibly the types as well, to the caller. This doesn't have to be done by directly passing the number of arguments, there are other methods such as the one used in printf.
You could pass a sentinel to the function like this
strtest("s", (char*)0);
such that the function can notice that it is at the end of the argument list.
If you look at the man page for stdarg, va_arg includes this text
If there is no next argument, or if type is not compatible with the
type of the actual next argument (as promoted according to the
default argument promotions), random errors will occur.
Unless you call strtest with a NULL as the last argument, va_arg will just keep reading until it hits something that makes it stop. Think of what you are doing right now as equivalent to reading an array outside its bounds.
I'm surprised it was running 4 times no matter what though. I would have expected the count to be equal to the number of args you passed to strtest plus 2 or more.

Function with unknown number of parameters in C

How can I write (if it's possible at all...) a function which takes an unknown number of parameters in C99 (the return type is constant)?
Yes you can do it in C using what are referred to as Variadic Functions.
The standard printf() and scanf() functions do this, for example.
Put the ellipsis (three dots) as the last parameter where you want the 'variable number of parameters to be.
To access the parameters include the <stdarg.h> header:
#include <stdarg.h>
And then you have a special type va_list which gives you the list of arguments passed, and you can use the va_start, va_arg and va_end macros to iterate through the list of arguments.
For example:
#include <stdarg.h>
int myfunc(int count, ...)
{
va_list list;
int j = 0;
va_start(list, count);
for(j=0; j<count; j++)
{
printf("%d", va_arg(list, int));
}
va_end(list);
return count;
}
Example call:
myfunc(4, -9, 12, 43, 217);
A full example can be found at Wikipedia.
The count parameter in the example tells the called function how many arguments are passed. The printf() and scanf() find that out via the format string, but a simple count argument can do it too. Sometimes, code uses a sentinel value, such as a negative integer or a null pointer (see
execl()
for example).

Resources