As a part of my program I use:
int ret = vprintf (format, args);
The args I get on the stack and I can't know what actually was pushed on the stack.
The format is a string, which I can read.
The above approach works until I have to print floats. When I print float I get some strange numbers ...
I checked that if I call float fArg = *(reinterpret_cast<const float*>(args) - and then print fArg the correct value is printed (I tried it when args was consisted only from one actual argument)
So probably I need special behavior for "%...f" sub-format - the corresponding (sub)argument should be cast
to float. (The ... notation means that precision, width etc. could be added before f)
How can I implement it?
Note that with variable-length argument lists, all float values are promoted to (and passed as) double values. You cannot reliably use:
float f = va_arg(args, float); /* BAD! */
because the language never places a float value on the stack. You would have to write:
float f = va_arg(args, double); /* OK */
This may be your entire problem.
If not, it is likely that you will need to scan the format string, and isolate the format specifiers, and implement a significant portion of the core printf() code. For each specifier, you can collect the appropriate value from the args. You then simply call the appropriate printf() function on a copy of the initial segment of the format string (because you can't modify the original) with the correct value. For your special case, you do whatever it is you need to do differently.
It would be nice to be able to pass the args parameter to vprintf() so it deals with collecting the type, etc, but I don't think that's portable (which is undoubtedly a nuisance). After you've passed a va_list value such as args to a function that uses va_arg() on it, you cannot reliably do anything other than va_end() on the value after the function returns.
Earlier this year, I wrote an printf()-style format string analyzer for POSIX-enhanced format strings (which support the n$ notation to specify which argument specifies a particular value). The header I created contains (along with enumerations for PFP_Errno, PFP_Status, FWP_None and FWP_Star):
typedef struct PrintFormat
{
const char *start; /* Pointer to % symbol */
const char *end; /* Pointer to conversion specifier */
PFP_Errno error; /* Conversion error number */
short width; /* Field width (FPW_None for none, FPW_Star for *) */
short precision; /* Field precision (FPW_None for none, FPW_Star for *) */
short conv_num; /* n of %n$ (0 for none) */
short width_num; /* n of *n$ for width (0 for none) */
short prec_num; /* n of *n$ for precision (0 for none) */
char flags[6]; /* [+-0# ] */
char modifier[3]; /* hh|h|l|ll|j|z|t|L */
char convspec; /* [diouxXfFeEgGAascp] */
} PrintFormat;
/*
** print_format_parse() - isolate and parse next printf() conversion specification
**
** PrintFormat pf;
** PFP_Status rc;
** const char *format = "...%3$+-*2$.*1$llX...";
** const char *start = format;
** while ((rc = print_format_parse(start, &pf)) == PFP_Found)
** {
** ...use filled in pf to identify format...
** start = pf.end + 1;
** }
** if (rc == PFP_Error)
** ...report error, possibly using print_format_error(pf.error)...
*/
extern PFP_Status print_format_parse(const char *src, PrintFormat *pf);
extern const char *print_format_error(PFP_Errno err);
extern PFP_Status print_format_create(PrintFormat *pf, char *buffer, size_t buflen);
The parse function analyzes the source and sets the appropriate information in the structure. The create function takes a structure and creates the corresponding format string. Note that the conversion specifier in the example (%3$+-*2$.*1$llX) is valid (but a little dubious); it converts an unsigned long long integer passed as argument number 3 with a width specified by argument 2 and a precision specified by argument 1. You probably could have a longer format, but only by a couple of characters without repetition, even if you used tens or hundreds of arguments in total.
There's no easy, portable way to do this; to inspect a va_list, you must know what types of values it holds and the only way to know is by parsing the format string. Effectively, you'll have to reimplement part of vprintf. (Part, because you can still send off the individual format specifier + cast value pairs to printf and not worry about how to pick apart a float.)
Related
I am trying to build a parser to a given input, there are 8 possible commands. So I figured that instead of using the ugly technique of a case switch block like that:
switch(command)
case cmd1:
.... /*call a function that do cmd1*/
case cmd2
..../*call a function that do cmd2*/
I will define in a header an array of structs, each one contains the name of the function, and a pointer to a function:
typedef struct command_info
{
char *name;
void (*func)(int)
};
command_info command_table[] = {{"func1", &func1}, {"func2", &func2} }
So that I can switch to the more elegant:
int i;
for(i = 0; i < COMMAND_TABLE_LENGTH; i++)
if(!strcmp(command_table[i].name, command))
command_table[i].func(2);
My only problem is, that the functions have different parameters (all return void). This is not a problem for me since I can check if the function is func1 or func2 search for one int argument for example, and if it is func3 or func4 search for two (still more compact than case switch). But the function pointer only points to a function with a certain type and amount of arguments. How can I make a universal pointer that can point to any function?
But the function pointer only points to a function with a certain type and amount of arguments.
How can I make a universal pointer that can point to any function?
In OP's limited case, use void (*func)().
Any function pointer can be converted with a type cast to another function pointer and retain an equivalent function address. #Jonathan Leffler
int (*foo)(int) = (int (*)(int)) sqrt;
double (*sq)(double) = (double (*)(double)) foo;
printf("%f\n", sq(2)); // prints 1.414214
A function pointer need not provide a function parameter signature.
// No parameter info
// vv
int (*foo)() = (int (*)()) sqrt;
OP has "functions have different parameters (all return void)", so in OP's case code could use a limited universal function pointer of void (*func)() and lose parameter checking.
typedef struct {
char *name; // suggest const char *name
void (*func)(); // no parameter info nor checking
} command_info;
char buf[100];
// void setbuf(FILE * restrict stream, char * restrict buf);
command_info fred = { "my_setbuf", setbuf };
// Both compile, 2nd is UB.
fred.func(stdin, buf); // No parameter checking.
fred.func(0); // No parameter checking.
Code also incurs a subtle issue when calling .funf(): the parameters ranking lower than int/unsigned are promoted as well as float parameters before passed to the function. Best to make certain the parameters are not char, float, short, _Bool etc. to avoid compatible signature issues.
void * is a universal object pointer. It may be insufficient to encode a function pointer. So it is not a portable candidate. It is not uncommon for the size of a function pointer to be wider than sizeof(void*).
I have some problems in my code:
UINT8 PoWerSignal = MyScanResults.signal;
char Signal[8];
sprintf(Signal, "%d", PoWerSignal);
float decibel = 0;
decibel = 10 * log(Signal);
dbgwrite("SIGNAL: ");
_dbgwrite(decibel);
There is one error:
error: incompatible type for argument 1 of 'logf'
I don't know how to fix this or what it means.
Your are passing a char array (aka "string", here: Signal, the alphanumerical representation of the value stored in PoWerSignal) to log(), which most likely does not expect such input, but a number.
You might like to pass the numerical representation of the function log()like so:
#include <stdio.h> /* To have the prototypes foe the printf family of functions. */
...
UINT8 PoWerSignal = MyScanResults.signal;
char Signal[8] = "";
snprintf(Signal, sizeof(Signal), "%d", PoWerSignal);
float decibel = 10. * log(PoWerSignal);
...
The function _dbgwrite() seems to expect an char array on the other hand. To conform to this create the a "string" using snprintf() out of decibel to pass into it, like so:
...
char descibel_str[64] = "";
snprintf(decible_str, sizeof(decibel_str), "%f", (double) decibel);
dbgwrite("SIGNAL: ");
_dbgwrite(decibel_str);
Note on the usage of snprintf() instead of sprintf(): The former version of this "conversion" function does take care of not overflowing the target buffer, that is where the alphanumerical representation of the arguments passed are stored. This can easely happend and would provoke undefined behaviour.
Looks like you're sending a bad data type (signal). Perhaps this should be a float or unsigned int instead of a character array? "char" denotes a string of text, and you can't operate on it as a number.
I am trying to learn C and am very confused already.
In the OOP languages i have used there exists the ability to perform method overloading, where the same function could have different parameter types and call whichever was the most appropriate.
Now in C i know that this is not the case so i cant figure out the following problem, How printf() works.
For example:
char chVar = 'A';
int intVar = 123;
float flVar = 99.999;
printf("%c - %i - %f \n",chVar, intVar, flVar);
printf("%i - %f - %c \n",intVar, flVar, chVar);
printf("%f - %c - %i \n",flVar, chVar, intVar);
Now as C does'nt support function overloading, How does printf manage to take any number of arguments, of any type, and then work correctly with them?
I have tried to find the printf() working by downloading the glibc source package but can quite seem to find it, though i'll keep looking.
Could anyone here explain how C performs the above task?
C supports a type of function signature called "varargs" meaning "variable (number of) arguments". Such a function must have at least one required argument. In the case of printf, the format string is a required argument.
Generally, on a stack-based machine, when you call any C function, the arguments are pushed onto the stack from right-to-left. In this way, the first argument to the function is that found on the "top" of the stack, just after the return address.
There are C macros defined which allow you to retrieve the variable arguments.
The key points are:
There is no type-safety for the variable arguments. In the case of printf(), if the format string is wrong, the code will read invalid results from memory, possibly crashing.
The variable arguments are read through a pointer which is incremented through the memory containing those arguments.
The argument pointer must be initialized with va_start, incremented with va_arg, and released with va_end.
I have posted a ton of code you may find interesting on the related question:
Best Way to Store a va_list for Later Use in C/C++
Here's a skeleton of a printf() which only formats integers ("%d"):
int printf( const char * fmt, ... )
{
int d; /* Used to store any int arguments. */
va_list args; /* Used as a pointer to the next variable argument. */
va_start( args, fmt ); /* Initialize the pointer to arguments. */
while (*fmt)
{
if ('%' == *fmt)
{
fmt ++;
switch (*fmt)
{
case 'd': /* Format string says 'd'. */
/* ASSUME there is an integer at the args pointer. */
d = va_arg( args, int);
/* Print the integer stored in d... */
break;
}
}
else
/* Not a format character, copy it to output. */
fmt++;
}
va_end( args );
}
Internally, printf will (at least usually) use some macros from stdarg.h. The general idea is (a greatly expanded version of) something like this:
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int my_vfprintf(FILE *file, char const *fmt, va_list arg) {
int int_temp;
char char_temp;
char *string_temp;
char ch;
int length = 0;
char buffer[512];
while ( ch = *fmt++) {
if ( '%' == ch ) {
switch (ch = *fmt++) {
/* %% - print out a single % */
case '%':
fputc('%', file);
length++;
break;
/* %c: print out a character */
case 'c':
char_temp = va_arg(arg, int);
fputc(char_temp, file);
length++;
break;
/* %s: print out a string */
case 's':
string_temp = va_arg(arg, char *);
fputs(string_temp, file);
length += strlen(string_temp);
break;
/* %d: print out an int */
case 'd':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 10);
fputs(buffer, file);
length += strlen(buffer);
break;
/* %x: print out an int in hex */
case 'x':
int_temp = va_arg(arg, int);
itoa(int_temp, buffer, 16);
fputs(buffer, file);
length += strlen(buffer);
break;
}
}
else {
putc(ch, file);
length++;
}
}
return length;
}
int my_printf(char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(stdout, fmt, arg);
va_end(arg);
return length;
}
int my_fprintf(FILE *file, char const *fmt, ...) {
va_list arg;
int length;
va_start(arg, fmt);
length = my_vfprintf(file, fmt, arg);
va_end(arg);
return length;
}
#ifdef TEST
int main() {
my_printf("%s", "Some string");
return 0;
}
#endif
Fleshing it out does involve quite a bit of work -- dealing with field width, precision, more conversions, etc. This is enough, however, to at least give a flavor of how you retrieve varying arguments of varying types inside your function.
(Don't forget that, if you're using gcc (and g++?), you can pass -Wformat in the compiler options to get the compiler to check that the types of the arguments match the formatting. I hope other compilers have similar options.)
Could anyone here explain how C performs the above task?
Blind faith. It assumes that you have ensured that the types of the arguments match perfectly with the corresponding letters in your format string. When printf is called, all the arguments are represented in binary, unceremoniously concatenated together, and passed effectively as a single big argument to printf. If they don't match, you'll have problems. As printf iterates through the format string, every time it see %d it will take 4 bytes from the arguments (assuming 32-bit, it would be 8 bytes for 64-bit ints of course) and it will interpret them as an integer.
Now maybe you actually passed a double (typically taking up twice as much memory as an int), in which case printf will just take 32 of those bits and represented them as an integer. Then the next format field (maybe a %d) will take the rest of the double.
So basically, if the types don't match perfectly you'll get badly garbled data. And if you're unlucky you will have undefined behaviour.
I am tring to get sound samples from microphone through Fez Panda 2. I am using rlp to accomplish that. Here is my code:
int GHAL_AnalogIn_Read(unsigned char channel)
{
return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >>8) & 0x3FF;
}
int ReadAudio(unsigned int *generalArray, void **args, unsigned int argsCount ,unsigned int *argSize)
{
unsigned char *buffer = (unsigned char*)args[0];
int buffer_lengh = argSize[0];
unsigned char channel = *(unsigned char*)args[1];
int i=0;
while(i<buffer_lengh)
{
buffer[i] = GHAL_AnalogIn_Read(channel);
i++;
RLPext->Delay(100);
}
return 0;
}
The problem is that I need float values not unsigned char because I'm performing fft on these sound samples. So I need modification that will provide me float values. Any ideas?
Have you got experience with C? Especially with the meaning of * and &? * means: get the value pointed by address. So void ** args says someting like 'get the value pointed by the value obtained from address'. void is used to freely input anything you like. As you can not put whole structures or objects in an argument, you provide the pointer (an address) to a structure or object. By using the * you obtain the value on the address of the argument.
In C you do not pass whole arrays in an argument, you pass on the address of the first index.
Now you could simply re-factor your function to be something like:
int ReadAudio(unsigned int *generalArray, float arg, unsigned int argsCount ,unsigned int *argSize)
But as void **args is pointing to a buffer now, I think you should know what operation you want to perform on the data collected. An analog read will always provide you with an integer, most ADC (analog - digital - converter) are 10-bit or so.
If a float is 4 bytes on a 32-bit system, you want to mangle your data (unsigned char *buffer) in a 4-byte boundary.
EDIT: I have overlooked this in the documentatio: Note: Parameter of all function in RLP code file must have format follow this:Note: Parameter of all function in RLP code file must have format follow this:. Just cast the buffer bytes to a float by 4 byte boundary and I think you will do fine.
I have a function
void func(int x, char *str, ...)
{
...
}
I am invoking it as follows:
func(1, "1", "2", "3");
How can I print the values of all the extra arguments (2, 3) in function?
From the man page of STDARG about the use of va_arg to get the next argument:
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.
Hence, unless you want random errors to creep in, you should know the number of arguments beforehand.
Even so, if you want to throw caution to the winds, you could try:
void func(int x,char *str, ...)
{
va_list al;
va_start(al,str);
while(x>0)
{
str=va_arg(al,char *);
--x;
}
while(str != NULL)
{
printf("%s ",str);
str=va_arg(al,char *);
}
va_end(al);
}
With,
func(1,"1","2","3");
I got the output,
2 3 U��WVS�O
If it satisfies your purpose, you could pick out the required number of arguments from this output.
It is customary with variable arguments to pass a string which describes the variable arguments, e.g. printf( char *format_string, ... );
This is a solution - and the customary solution - to your problem.
Pass an additional argument which describes the variable arguments, and then use that information to process the variable arguments.
So, if you receive a printf-like format string and it is "%d%u", you know you have an int, followed by an unsigned int.
lookup va_list in this site. Example: What is ellipsis operator in c