Is it possible to iterate through variadic function' arguments using pointer (void pointer?) to last named argument? (I know that's not the right way to work with variadic arguments, but I'm still interested if that would work)
Setting pointer to the end of the string doesn't work, because after I start moving the pointer, it points to other strings used in the program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void form_date(MON* datePtr, int dayMonth, int dayYear, int month);
MON* evaluate_date(MON* datePtr, int count, int dayArg);
void what_month(char *format, ...);
void output(MON* datePtr, int count);
int main(void)
{
what_month("ii", 126, 125);
return 0;
}
void what_month(char *format, ...){
char* arg_ptr = format+2;
int* arg_int_ptr;
double* arg_double_ptr;
MON dateArr[MAX_DATE];
int count = 0;
int dayYear;
char *ptrFormat = format;
for(; *ptrFormat != '\0'; ptrFormat++){
if(*ptrFormat == 'i'){
arg_int_ptr = (int*) arg_ptr;
dayYear = *arg_int_ptr;
arg_int_ptr++;
}
if(*ptrFormat == 'd'){
arg_double_ptr = (double*) arg_ptr;
dayYear = *arg_double_ptr;
arg_int_ptr++;
}
evaluate_date(dateArr, count, dayYear);
count++;
}
output(dateArr, count);
}
void form_date(MON* datePtr, int dayYear, int dayMonth, int month){
char month_names[][15] = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November",
"December", "INVALID_MONTH"};
datePtr->day_of_year = dayYear;
datePtr->day_of_month = dayMonth;
if(month == -1){
strcpy(datePtr->month, month_names[12]);
}
else {
strcpy(datePtr->month, month_names[month]);
}
}
MON* evaluate_date(MON* dateArr, int count, int dayArg){
int months_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int j;
int dayMonth;
int sumDays = 0;
if (dayArg > 365 || dayArg < 1){
form_date(dateArr + count, dayArg, -1, -1);
count++;
}
else {
for(j = 0; j < 12; j++){
sumDays += months_days[j];
if (dayArg <= sumDays)
break;
}
dayMonth = months_days[j] - (sumDays - dayArg);
sumDays = 0;
if (dayMonth == 0){
dayMonth++;
}
form_date(dateArr + count, dayArg, dayMonth, j);
}
return dateArr;
}
void output(MON* dateArr, int count){
int i, j;
for(i = 0; i < 80; i++)
printf("_");
printf("\n");
for(i = 0; i < 80; i++)
printf("_");
for(j = 0; j < count; j++){
if (j % 100 == 0 && j != 0){
puts("Press any key to continue");
getchar();
}
printf("\n%-7d ::: %7d, %-8s %5s\n", dateArr[j].day_of_year, dateArr[j].day_of_month,
dateArr[j].month, "|");
}
for(i = 0; i < 80; i++)
printf("_");
}
No, you cannot do that portably. To use variable function arguments you must use the facilities provided in <stdarg.h>
.
You can, however, look at your platform's code generation and/or machine code output and get an understanding of the machine layout of the variable arguments, and perhaps use that for your own, platform-specific purposes.
First - strings are not passed via value in C/C++ unless encapsulated in some struct/class so on the stack you'll find a pointer to a string not a string itself.
You should not handle variable argument list manually using pointers as that is not portable in first place.
Why not portable ? Here are some problems:
Moreover in standard calling convention for C/C++ your last argument is pushed on stack first so you cannot use it for variadic functions (as you cannot immediately locate it fromyour func). cdecl calling convension pushes arguments on stack in reversed order ie.:
func(a,b)
is
push b
push a
call func
This reversed convention is only for the purpose of allowing variadic functions to work since your first argument a (which is always needed in varargs) can always be easily accessed from stack as it's location is known (because pushed last). To get other arguments (or to understand how many they are, or their types) you usually must parse first argument - just like in printf.
Hope this sheds some ligh on that.
Some additional info that may help:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With