Thursday, May 23, 2013

C/C++: Variable number of arguments to a function(2)

Summary: This post discuses va_copy and its uses. There is a code below that shows its use.

This is my second post on the topic. If you dont know how these va_* macros work, you may want to read my previous post on this topic. When you learn the concept for the first time, you are tempted to believe that its a great idea to have a lot of functions of this type. Wont that be a great flexibility to have all the time? Unfortunately, thats not true. The problem is:

  1. va_arg() assumes the elements in va_list object to be of a given data type. So, you must know the types in advance to be able to extract the values from the va_ist object.

  2. Once you have traversed a va_list object, you can not get the first element again by resetting the pointers in for the same object.


Lets talk about the possible problems with (2). Lets try out various ways of getting the pointers reset to the beginning of the va_list object. Lets assume we have va_list "src" as the given list which we have traversed and "dest" as a copy of the same list. We want to be able to get the first element of the va_list after src has traversed  the complete va_list object once. On that route, lets first think what a possible implementation of va_list would do. The first thing that comes to mind is that a va_list object could be a pointer to the stack frame of the variadic function. In this situation, it seems perfectly alright to make an assignment say,
va_list dest = src;

Unfortunately, that doesnt work all the time. The next possibility could be that the va_list object is an array of pointers pointing to individual arguments in the variable argumet list , So, we can do a
va_list dest;
*dest = *src;

But that is also not the foolproof way because, on certain systems where arguments are passed in registers, it may be necessary for va_start() to allocate memory, store the arguments there, and also an indication of which argument is next, so that va_arg() can step through the list. Now va_end() can free the allocated memory again. So, there is no way you will be able to access that element again. But all is not gloomy my friend  for the standard thus defines an interface in the name of va_copy() , so that the above assignments can be replaced by

va_list dest;
va_copy(dest, src);
...
va_end(dest);


And this is a foolproof way !!! Finally :)
Note that the compiler wont complain about the wrongdoings in the methods discusses above. The compilation and linking will all pass fine, only when you see the outputs they will appear weird.  The good news is, you can always use va_copy() function to get a replica of a va_list object at that instant of time. So, if you want to use the variable argument list a second time, just use this function. The prototype is:
void va_copy (va_list destination, va_list source);

Just remember that each invocation of va_copy() must be matched by a corresponding invocation of va_end() in the same function. Lets now look at a small code to see va_copy() in action.

[sourcecode language="cpp"]

#include<stdio.h>
#include <stdarg.h>

/* The sum() function can accept variable number of arguments.
In the function declaration "..." at the end means that the
number and type of the arguments may vary. The marker ... can
only appear at the end.
*/
int sum(int num_of_arguments, ... )
{
/* A list to store the aruements. In example, this may contain
1,2,3 and 4 elements on successive calls from main()
*/
va_list args;
int sum= 0, i;

/* Directing the va_list args initialized above to start storing
all parameters folloowing the first parameter 'num_of_arguments'
*/
va_start (args, num_of_arguments );

va_list args_copy; //initialize a copy of va_list to be used
va_copy(args_copy, args); //copy args to args_copy

for (i= 0; i< num_of_arguments; i++ )
/* We add 5 to each element in variable argument list and
print it.
*/
printf("%d ", va_arg (args_copy, int) + 5);

va_end(args_copy); //destruct args_copy

printf("\n");

/**** Next, we use args as in previous post ****/

/* Loop until all parameters are seen. */
for (i= 0; i< num_of_arguments; i++ )
/* Extract the next value in argument list and add it to sum. */
sum += va_arg (args,int);

/* Signal that we are done with our usage of the list */
va_end (args);

return sum; /* Returns the calculated sum.*/
}
int main()
{
int result;

result=sum (4,1,2,3,4);
printf("result of sum() with 5 arguement: %d \n", result);

return 0;
}

[/sourcecode]

Play with the above code on ideone. Change a few things here and there and see how it works.

Happy coding !!!

References:

Saturday, May 18, 2013

C/C++ - Variable number of arguments to a function

Ever wondered how printf() in C would be implemented ? If you are a C-lover, I guess you would have, for its a function that looks pretty different from the other library functions, consumes tons of options and its very powerful. If you are not a C-fan and do not know much of it, you may want to have a look here . Well, one of the great flexibility of printf() comes from the fact that it can consume variable number of arguments. If you are scratching your head about how it does that, hold on,  you will know it in a minute. That is what this post aims at :) . Lets look at some examples to understand what 'variable number of arguments' means.

[sourcecode language="c"]

#include<stdio.h>
int main()
{
char * string = "with";
printf("printf with 1 arguement\n");
printf("Printf with %d arguements\n", 2);
printf("Printf %s %d arguements", string, 3);
return 0;
}
[/sourcecode]

Note that the first version takes one argument, the second version takes two arguments and the third takes three. Have you ever written a function definition in C that can be invoked with any number of arguements 1...N ? If not, lets write one. But on the way we need to learn a couple of things as ingredients to it. We need to know of four simple things. The definitions have been taken from cplusplus.com. If you dont understand what they mean, you may first want to see how they are used ( see the code below) and believe me, its very simple to understand them from the usage.

  1. va_list:  Type to hold information about variable arguments.
     Objects of this type can only be used as argument for the  va_start,  va_arg,  va_end and  va_copy macros, or functions that use them, like the variable argument functions in <cstdio>  (vprintf,  vscanf,  vsnprintfvsprintf and  vsscanf).


  2. void va_start (va_list ap, paramN)

    Initialize a variable argument list. Initializes ap to point to the first unnamed argument. It retrieve the additional arguments after parameter paramN. A function that invokes va_start(), should also invoke va_end() before it returns.


  3. type va_arg (va_list ap, type)

    Retrieve next argument. This macro expands to an expression of type type with the value of the current argument in the variable arguments list identified by ap.


  4. void va_end (va_list ap);

    Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function.. It performs the appropriate actions to facilitate a normal return by a function that has used the va_list object ap .


Pheww thats a lot of technical Jargon !! Lets revert to some simpler words now. In short, you need to first define a list of type va_list by saying something like.. va_list args. Next, invoke a call to va_start() to indicate where the variable list of arguments  starts from, extract each argument from the variable list (args in our case) using va_arg() and finally dont forget calling va_end().

Note that apart from va_ag(), a va_list object (named ap in declarations below ) can also be consumed by versions of printf() that are preceded by 'v', for example:

  1. int vprintf ( const char * format, va_list ap ); - Prints formatted data from variable argument list to stdout,

  2. int vfprintf ( FILE * stream, const char * format, va_list ap ); - Writes formatted data from variable argument list to stream and

  3. int vsprintf (char * s, const char * format, va_list ap ); - Writes formatted data from variable argument list to string s.


Lets look at an example that uses the a va_arg(). For the above mentioned printf versions, you can find a C program for each of the 3 functions listed above in the links in the "References" section  (#2, #3, #4 respectively) at the end of this post.

[sourcecode language="c"]
#include<stdio.h>
#include <stdarg.h>

/* The sum() function can accept variable number of arguments.
In the function declaration ... means that the number and
type of the arguments may vary. The marker ... can only
appear at the end.
*/
int sum(int num_of_arguments, ... )
{
/* A list to store the aruements. In example, this may contain
1,2,3 and 4 elements on successive calls from main()
*/
va_list args;
int sum= 0, i;

/* Directing the va_list args initialized above to start storing
all parameters folloowing the first parameter 'num_of_arguments'
*/
va_start (args, num_of_arguments );

/* Loop until all parameters are seen. */
for (i= 0; i< num_of_arguments; i++ )
/* Extract the next value in argument list and add it to sum. */
sum += va_arg (args,int);

/* Signal that we are done with our usage of the list */
va_end (args);

return sum;  /* Returns the calculated sum.*/
}
int main()
{
int result;

result=sum (1,1);
printf("result of sum() with 2 arguement: %d \n", result);

result=sum (2,1,2);
printf("result of sum() with 3 arguement: %d \n", result);

result=sum (3,1,2,3);
printf("result of sum() with 4 arguement: %d \n", result);

result=sum (4,1,2,3,4);
printf("result of sum() with 5 arguement: %d \n", result);

return 0;
}
[/sourcecode]

Time to see what the function outputs. Here you go:
result of sum() with 2 arguement: 1 
result of sum() with 3 arguement: 3
result of sum() with 4 arguement: 6
result of sum() with 5 arguement: 10

And as always play with the above  code on ideone. Change a few things here and there and see how it works. Done with this? Lets try and implement our own version of printf().

References:

  1. Linux man page: http://linux.die.net/man/3/va_arg

  2. http://www.cplusplus.com/reference/cstdio/vprintf/

  3. http://www.cplusplus.com/reference/cstdio/vfprintf/

  4. http://www.cplusplus.com/reference/cstdio/vsprintf/

Sunday, May 5, 2013

C++ : The good old thing

Today, I remember a comment from a friend of mine when I started into the world of programming taking up a course in C++. He said "Dude, C++ is an old thing. Who uses it today? Arent there fancier suff out there? And why would someone take a C++ route?"  That was my first day at programming. I didnt know much about these languages to have a good answer to that. But, 8 years later I have an answer to it. Yes, Thats a pretty long time. But I know what I like now and that is what the title of the post says. Yes, To me, it comes as a trade off between the needs to prioritize development speed over execution speed, which is where all these “fancy” languages tend to shine. In my experience, these other languages execute fast enough on smaller projects, but start to break down on larger ones. If you still dont agree look at the list of software written in C. Thats a big fat list with some of the most used software out there. Here is a list on the same. Pheww thats loooong. Isnt it? Well, I cant guarantee the authenticity of each and every item on that list but I see names of which I know that they are written in C++. So, I do trust it.

As much as C++’s large feature set and "strict" syntax may be seen as a complex thing for newbies to master, it is about giving the power to express everything one wants directly, unlike any other “simpler” language. I cant stop myself from throwing out something I  read on wiki recently.
 A widely distributed "satirical" article portrayed Bjarne Stroustrup confessing that C++ was deliberately designed to be complex and difficult, weeding out amateur programmers and raising the salaries of the few programmers who could master the language :D.

Yes, thats the challenge. You have all the design tools and if you have the expertise you will definitely love C++. As a matter of fact, I love C for that matter because it gives all the more development speed but then I think its incomplete without all the features and libraries C++ offers on top of it. C++ with its object oriented capability and STL looks a lot more powerful. And with the latest addition being C++11 it adds to the power. Here is a list of things I see in C++11 which excites all the more. Though I am not sure about the stability of all these set of features, it definitely pleases me on the first look. Its time to get your hand dirty trying out all these. Lets have a look at the list:

1) Important Syntax cleanup
2) Automatic type deduction with Auto
3) Range Based for loops
4) Lambda Functions
5) standardized support for multithreaded programming.
6) regex support
7) Chrono library to deal with time duration and points
8) Containers such as unordered_map, unordered_set and Tuples etc
9) Headers for random number generation and ration class templates.

I will try and cover a post on each of these in future. But for now, lets play around with these
new tools. And once the tools are sharpened lets discus them.

Cheers !!!