Get variable arguments directly from stack - c

I'm playing with the stack and function's call parameters.
What I want to achieve here is to get the value of variable parameters directly using the stack.
It works (or seems to work) fine when I don't use variable parameters.
Here is what is working:
void test(int a, int b)
{
unsigned char *ptr;
int i;
ptr = (unsigned char*)&a;
for (i = 0; i < 4; i++)
{
printf("%d,", *ptr);
}
}
That works, I can retrieve the value of b;
The same code using
void test(int a, ...);
as function's prototype doesn't work.
I cant understand what's going on here.
Can you help me?
Thanks !
Edit:
Ok, then it seeems there is no stable and reliable way to do that kind of stuff on my own.
Lets say that in the callee function I know the data size (but not the type) of variable argument, is there a way to grab them ?

As long as you know or can determine the number of arguments, you can use the macros from <stdarg.h>:
#include <stdio.h>
#include <stdarg.h>
void test1(int n, ...)
{
va_list args;
va_start(args, n);
for (int i = 0; i < n; i++)
{
int j = va_arg(args, int);
printf("%d: %d\n", i, j);
}
va_end(args);
}
void test2(int a, ...)
{
va_list args;
int i = 0;
printf("%d: %d\n", i++, a);
va_start(args, a);
int j;
while ((j = va_arg(args, int)) > 0)
printf("%d: %d\n", i++, j);
va_end(args);
}
The difference is in how these two functions are called:
int main(void)
{
test1(4, 1, 3, 7, 9);
test2(1, 3, 7, 9, 0);
return(0);
}
The printf() family uses an alternative but equivalent technique; those functions scan the format string and determine the type of each argument (as well as the number of arguments) from the information in the format string. So, your main options are:
count - test1()
sentinel - test2()
format string - printf()

In functions with ... you can use va_* macro
void test(int a, ...) {
va_list ap;
va_start(ap, a);
// Your code
va_end(ap);
}

Related

Why does this variadic C function not print the first argument?

I am trying to make a variadic function in C with stdarg.h, and I followed this tutorial and wrote the code exactly as he did: https://www.youtube.com/watch?v=S-ak715zIIE. I included the output in the code. I cannot figure out why the first argument is not printed, and also, why are there zeros printed at the end? I am beyond confused. Thanks!
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
for (int i = 0; i < num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(5, 2, 3, 4);
return 0;
}
/*
Output:
0: 2
1: 3
2: 4
3: 0
4: 0
*/
va_start's first argument is the last parameter that isn't variadic. So num holds the 5, and the rest hold the variadics:
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
printf("%d: %d\n", 0, num);
for (int i = 1; i <= num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(5, 2, 3, 4);
return 0;
}
0: 5
1: 2
2: 3
3: 4
4: 0
5: 0
also, why are there zeros printed at the end? I am beyond confused. Thanks!
Because of this line:
for (int i = 1; i <= num; i++) {
You pass the value 5 as num to printNums(). In the for loop you act as though it describes the number of variadic arguments to read, but it doesn't - you passed 3 variadics, not 5. The last 2 calls to va_start therefore yield undefined behavior, since you've read past the end of valid variadic arguments. It's just mere chance that you happen to get 0 here - it could be some other random value.
Note that there is no way with mere variadic macros to know how many arguments were passed. Nor is there a way to assert their type. You can assume their type and specify their length at runtime if you wish:
$ ./t3
0: 5
1: 2
2: 3
3: 4
#include <stdio.h>
#include <stdarg.h>
void printNums(int num, ...) {
va_list args;
va_start(args, num);
for (int i = 0; i < num; i++) {
int value = va_arg(args, int);
printf("%d: %d\n", i, value);
}
va_end(args);
}
int main() {
printNums(4, 5, 2, 3, 4);
return 0;
}
Variadic functions are primarily valuable when writing functions like printf, where unknown types and quantities of arguments are required (see the example from the man page) Using passing a list of known types would be more conveniently accomplished by passing an array and count int:
$ cat t.c
#include <stdio.h>
void printNums(int count, int* nums) {
for (int i = 0; i < count; i++) {
printf("%d: %d\n", i, nums[i]);
}
}
int main() {
int nums[] = {5,2,3,4};
printNums(4, nums);
return 0;
}
that just doesn't make a very good video about variadics :P

Variable number of arguments in C programmng

Whenever we use variable argument function in C language, we have to provide the total number of arguments as the first parameter. Is there any way in which we can make a function with variable arguments without giving the total number of arguments?
[update from comment:]
I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there.
Several ways:
pass simple, explicit count (which you don't want in this question)
pass some format string, similar to printf and scanf
pass some "mode" parameter, and have each mode require specific varargs
have all varargs to be of same type, and require last argument to be some special value, AKA sentinel value, such as NULL for pointer list or max/min value of the type for integer types, or NaN for doubles.
However you do it, you have to have some way for the function to know the types of the varargs, as well as a way for it to know when they end. There is no built-in way in C, argument count is not passed to the function.
I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there
You could define a sentinel. In this case 0 might make sense.
/* Sums up as many int as required.
Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
int s = i;
if (s)
{
va_list ap;
va_start(ap, i);
/* Pull the next int from the parameter list and if it is
equal 0 leave the while-loop: */
while ((i = va_arg(ap, int)))
{
s += i;
}
va_end(ap);
}
return s;
}
Call it like this:
int sum(int i, ...);
int main(void)
{
int s = sum(0); /* Gives 0. */
s = sum(1, 2, 3, 0); /* Gives 6. */
s = sum(-2, -1, 1, 2, 0); /* Gives 0. */
s = sum(1, 2, 3, 0, 4, 5, 6); /* Gives 6. */
s = sum(42); /* Gives undefined behaviour! */
}
The sum() function alternatively could also look like this (but would do one useless addition of 0):
/* Sums up as many int as required.
Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
int s = i;
if (s)
{
va_list ap;
va_start(ap, i);
/* Pull the next int from the parameter list and if it is
equal 0 leave the do-loop: */
do
{
i = va_arg(ap, int);
s += i;
} while (i);
va_end(ap);
}
return s;
}
You don't have to supply that number of arguments. For instance, consider the signature for printf:
int printf( const char* format, ... );
It "finds out" how many arguments it needs by parsing the string you give it. Of course, your function needs to know the amount of arguments in some way, otherwise what sense does it make for it to take a variable number of arguments?
It is possible to create a variadic function which takes a count as the first argument, then use variadic macros to add the count value automatically:
#include <stdarg.h>
#define count_inner(a1, a2, a3, a4, a5, num, ...) (num)
#define count(...) count_inner(__VA_ARGS__, 5, 4, 3, 2, 1)
#define sum(...) sum_func(count(__VA_ARGS__), __VA_ARGS__)
int sum_func(int count, ...)
{
va_list ap;
va_start(ap, count);
int total = 0;
while(count--)
total += va_arg(ap, int);
va_end(ap);
return total;
}
Using the sum macro instead of sum_func allows the count to be omitted, provided there are between 1 and 5 arguments. More arguments/numbers can be added to the count_inner/count macros as required.
int main(void)
{
printf("%d\n", sum(1));
printf("%d\n", sum(1, 2));
printf("%d\n", sum(1, 2, 3));
printf("%d\n", sum(1, 2, 3, 4));
}
Output:
1
3
6
10
Well, the problem is that you have to somewhat indicate to the function that your argument list is exhausted. You've got a method from printf(3) which is that you can express the order and the type of arguments in your first parameter (forced to be a string arg) you can express it in the first parameter, or, for the adding, as the value 0 doesn't actually add to the sum, you can use that value (or some other at your criteria) to signal the last parameter. For example:
int sum(int a0, ...)
{
int retval = a0;
va_list p;
va_start(p, a0);
int nxt;
while ((nxt = va_arg(p, int)) != 0) {
retval += nxt;
}
return retval;
}
This way, you don't have to put the number of arguments as the first parameter, you can simply:
total = sum(1,2,3,4,5,6,7,8,9,10,0);
But in this case you have to be careful, that you never have a middle parameter equal to zero. Or also you can use references, you add while your reference is not NULL, as in:
int sum(int *a0, ...)
{
int retval = *a0;
va_list p;
va_start(p, a0);
int *nxt;
while ((nxt = va_arg(p, int*)) != NULL) {
retval += *nxt;
}
return retval;
}
and you can have:
int a, b, c, d, e, f;
...
int total = sum(&a, &b, &c, &d, &e, &f, NULL);

variable-length-arguments in C [duplicate]

This question already has answers here:
Couldn't implement function with variable arguments
(1 answer)
Function with unknown number of parameters in C
(1 answer)
Closed 5 years ago.
I have learned that this code will print 10, 30, 60 in Terminal.
#include <stdio.h>
void add(int num, ...);
int main(int argc, char const *argv[])
{
int a=10, b=20, c=30;
add(1, a);
add(2, a, b);
add(3, a, b, c);
return 0;
}
void add(int num, ...)
{
int* p = NULL;
p = &num + 1;
if (num == 1)
printf("%d \n", p[0]);
else if (num == 2)
printf("%d \n", p[0] + p[1]);
else
printf("%d \n", p[0] + p[1] + p[2]);
}
But, it only print odd numbers... :(
I just want to print 10, 30, 60 within .
Where do you think I should fix?
You can't get variadic arguments just by taking the address of the last given parameter and adding to it. How function arguments are laid out on the stack (if a stack is used) is compiler and system dependent. That's why you're getting strange numbers.
The way to do this portably is to use a va_list as follows:
void add(int num, ...)
{
// the va_list used to retrieve the extra arguments
va_list args;
int i, sum = 0;
// use va_start to start processing arguments, passing in the last explicit argument
va_start(args, num);
for (i=0; i<num; i++) {
// extract the next argument with the given type
sum += va_arg(args, int);
}
// cleanup
va_end(args);
printf("%d \n", sum);
}
For more details, see the stdarg man page.

passing variable number of arguments

Can we pass variable number of arguments to a function in c?
Here is an example:
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
int main(void){
f();
exit(EXIT SUCCESS);
}
int maxof(int n_args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n_args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n", maxof(3, i, j[42], 0));
}
If it is a function that accepts a variable number of arguments, yes.
Yes, if the function accepts variable arguments. If you need to make your own variable-argument function, there are macros that begin with va_ which give you access to the arguments.
make sure that the variable argument list should always be at the end of the argument list
example: void func(float a, int b, ...) is correct
but void func(float a, ..., int b) is not valid
"You should consider that using variadic functions (C-style) is a dangerous flaw," says Stephane Rolland. You can find his helpful post here.

How can I pass any number of arguments in User define function in C?

How can I pass any number of arguments in User define function in C?what is the prototype of that function?It is similar to printf which can accept any number of arguments.
Look here for an example.
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT SUCCESS);
}
int maxof(int n args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
Such a function is calle variadic, but such functions are much less useful than they might at first seem. The wikipedia page on the topic is not bad, and has C code.
The basic problem with such functions is that the number of parameters cannot in fact be variable - they are must be fixed at compile time by a known parameter. This is obvious in printf:
printf( "%s %d", "Value is", 42 );
The number of % specifiers must match the number of actual values, and this is true for all other uses of variadic functions in C, in one form or another.

Resources