How to count the no of arguments passed to the function in following program:
#include
#include
void varfun(int i, ...);
int m
Appending or NULL at the end makes it possible for me to have any number of arguments and not worry about it going out of the stack
#include <cstdarg>
template<typename _Ty>
inline void variadic_fun1(_Ty param1,...)
{
va_list arg1;
//TO_DO
va_end(arg1);
}
template<typename _Ty>
void variadic_fun2(_Ty param1,...)
{
va_list arg1;
va_start(arg1, param1);
variadic_fun1(param1, arg1, 0);
va_end(arg1);
}
You can let the preprocessor help you cheat using this strategy, stolen and tweaked from another answer:
#include <stdio.h>
#include <stdarg.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_128TH_ARG(__VA_ARGS__)
#define PP_128TH_ARG( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,_64,_65,_66,_67,_68,_69,_70, \
_71,_72,_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88,_89,_90, \
_91,_92,_93,_94,_95,_96,_97,_98,_99,_100, \
_101,_102,_103,_104,_105,_106,_107,_108,_109,_110, \
_111,_112,_113,_114,_115,_116,_117,_118,_119,_120, \
_121,_122,_123,_124,_125,_126,_127,N,...) N
#define PP_RSEQ_N() \
127,126,125,124,123,122,121,120, \
119,118,117,116,115,114,113,112,111,110, \
109,108,107,106,105,104,103,102,101,100, \
99,98,97,96,95,94,93,92,91,90, \
89,88,87,86,85,84,83,82,81,80, \
79,78,77,76,75,74,73,72,71,70, \
69,68,67,66,65,64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
void _variad(size_t argc, ...);
#define variad(...) _variad(PP_NARG(__VA_ARGS__), __VA_ARGS__)
void _variad(size_t argc, ...) {
va_list ap;
va_start(ap, argc);
for (int i = 0; i < argc; i++) {
printf("%d ", va_arg(ap, int));
}
printf("\n");
va_end(ap);
}
int main(int argc, char* argv[]) {
variad(2, 4, 6, 8, 10);
return 0;
}
There's a few clever tricks here.
1) Instead of calling the variadic function directly, you're calling a macro that counts the arguments and passes the argument count as the first argument to the function. The end result of the preprocessor on main looks like:
_variad(5, 2, 4, 6, 8, 10);
2) PP_NARG
is a clever macro to count arguments.
The workhorse here is PP_128TH_ARG
. It returns its 128th argument, by ignoring the first 127 arguments (named arbitrarily _1
_2
_3
etc.), naming the 128th argument N
, and defining the result of the macro to be N
.
PP_NARG
invokes PP_128TH_ARG
with __VA_ARGS__
concatenated with PP_RSEQ_N
, a reversed sequence of numbers counting from 127 down to 0.
If you provide no arguments, the 128th value of PP_RSEQ_N
is 0. If you pass one argument to PP_NARG
, then that argument will be passed to PP_128TH_ARG
as _1
; _2
will be 127, and the 128th argument to PP_128TH_ARG
will be 1. Thus, each argument in __VA_ARGS__
bumps PP_RSEQ_N
over by one, leaving the correct answer in the 128th slot.
(Apparently 127 arguments is the maximum C allows.)
You can't. varargs aren't designed to make this possible. You need to implement some other mechanism to tell the function how many arguments there are. One common choice is to pass a sentinel argument at the end of the parameter list, e.g.:
varfun(1, 2, 3, 4, 5, 6, -1);
Another is to pass the count at the beginning:
varfun(6, 1, 2, 3, 4, 5, 6);
This is cleaner, but not as safe, since it's easier to get the count wrong, or forget to update it, than it is to remember and maintain the sentinel at the end.
It's up to you how you do it (consider printf's model, in which the format string determines how many — and what type — of arguments there are).
You can't. Something else has to tell you (for instance for printf, it's implied by the number of % format descriptors in the format string)
If you have a C99 compliant compiler (including the preprocessor) you can circumvent this problem by declaring a macro that computes the number of arguments for you. Doing this yourself is a bit tricky, you may use P99_VA_ARGS
from the P99 macro package to achieve this.
Read a pointer to pointers from EBP.
#define getReturnAddresses() void ** puEBP = NULL; __asm { mov puEBP, ebp };
Usage
getReturnAddresses();
int argumentCount = *((unsigned char*)puEBP[1] + 2) / sizeof(void*) ;
printf("CalledFrom: 0x%08X Argument Count: %i\n", puEBP[1], argumentCount);
Not portable, but I have used it in a x86 C++ detour of __cdecl method that took a variable number of arguments to some success.
You may need to adjust the -1 part depending on your stack/arguments.
I did not come up with this method. Suspect I may have found it on UC forums at some point.
I can't recommend to use this in propper code, but if you have a hacky detour on a x86 exe with __cdecl calling convention with 1 argument and then the rest are ... variable arguments it might work. (Win32)
Example calling convention of detour method.
void __cdecl hook_ofSomeKind_va_list(void* self, unsigned char first, ...)
Proof: Screen shot showing console output next to x32dbg on target process with a detour applied