C: Variable Argument List Access

Here, I explained how we can utilize the operator ellipsis (…) to pass variable number of arguments to a function. I have utilised there the concept of pointers to access the variable arguments. The standard C Library provides support to access these arguments. Use for this support
All you need is to know the last argument before the ellipsis operator(At least one argument is must to use variable arguments), let’s call it larg

suppose

    fun(type var1,type var2,...)

is a function, then larg corresponds to var2

Now we need to declare the list using va_list
i.e.,

    va_list al

now initialize it using va_start

    va_start(al,larg);

Now to access each argument, we must know the expected type of the argument

     type var_name = va_arg(al,type);

When we have accessed all the variable arguments, we need to clean up

     va_end(al);

Using standard library, we can easily access the variable arguments

Take a simple example

#include <stdarg.h>
int print(int num_count,...)
/*num_count contains the number of integers passed*/
{
  int i;
  va_list al;
  va_start(al,num_count);
  for(i=1;i<=num_count;i++){
     int val=va_arg(al,int);
     printf("%d ",val);
  }

}

int print_str(const char *str,...)
/*str has the number of strings passed*/
{
  int i;
  va_list al;
  int num_count=atoi(str);
  va_start(al,str);
  int *num=&num_count;
  for(i=1;i<=num_count;i++){
     char *str=va_arg(al,char *);
     printf("%s ",str);
  }

}

int main()
{
   print(3,2,3,4);
   print_str("3","Hi","All","!!!");
}

OUTPUT

2 3 4 Hi All !!!

 

C: Printing data types using printf : short, wchar_t, long double

printf is the most commonly used function while programming (for big developers at least in the designing stage). But we mostly come across the problem: “Which conversion character for char, short, pointers… and their unsigned counterparts?” Here is a program which deals with printing of all the different data types.

#include <stdio.h>

/*A program to see how diffent data types can be printed using printf
*See the conversion characters with % for the various data types
*/
int main()
{
    //Character strings
   char *message="Printing different data types";
   wchar_t *wmessage=L"Wide Character string";

   //Characters
   char ca='A';
   wchar_t wca=L'A';

   //Integer Data types
   unsigned short usa=65535; short ssb=-32768;
   unsigned int usi=4294967295; int ssi=-2147483648;
   unsigned long long int ulli=4294967295L;long long int lli=-2147483647L;

   //Floating point Data types
   float fa=1e+37,fb=1e-37;
   double da=1e+37,db=1e-37;
   long double lda=1e+37L,ldb=1e-37L;

   //Pointers
   int *p=&ssi;

   //Character strings
   printf("%s\n",message);
   printf("%ls\n\n",wmessage);

   //Character strings
   printf("%c\n",ca);
   printf("%lc\n\n",wca);

   printf("%hu %hi\n",usa,ssb); //short
   printf("%hx %hx\n\n",usa,ssb);

   printf("%u %i\n",usi,ssi); //integer/long integers
   printf("%x %x\n\n",usi,ssi);

   printf("%llu %lli\n",ulli,lli); //long long integers
   printf("%llx %llx\n\n",ulli,lli);

   printf("%f %f\n",fa,fb); //float

   printf("%f %f\n",da,db); //double
   printf("%e %e\n\n",da,db);

   printf("%llf %llf\n",lda,ldb); //long double
   printf("%lle %lle\n\n",lda,ldb);

   printf("%p\n\n",p); //pointer of any data type

}

Here’s the output

printf

C: #define, #ifdef, #ifndef, #else

#define is a C preprocessor. There are other ways of making the best usage of #define for writing efficient programs , for the purpose of testing and debugging, for deciding the course of action of the programs
When we first learn about #define, the commonly said example is define some commonly used values like PI, NAME_LEN ,… But there are other uses of #define.

Let me show some aspects of #define
The general syntax of #define

    #define identifier(identifier,..., indentifier) token_sequence

1. It is not necessary that all the identifiers used in token sequence is already defined

#define A B+20
#define B 10

As you can see that B was not defined when A is being defined. So the only condition is that we need to define it somewhere.

2. Using gcc, you can define macros and decide the course of your programming. For example, if I wish to perform debugging. I will define __DEBUG__ through gcc.To define macros using gcc, compile using the D option of gcc

gcc -Dmacro[=defn]...]

The following code snippet depicts this

#include <stdio.h>

/*This program shows how to make the use of #define to define the course

*of programming

*/

#define A B+20 /B is not defined here, but will be defined later/

#define B 10

int main()

{

#ifdef __DEBUG__
    printf("__DEBUG__ DEFINED\n");

    printf("%d\n",A);

#else

   printf("__DEBUG__ not defined\n");

   printf("%d\n",B);

#endif

return 0;
}

If I compile

$gcc test.c

Output:

__DEBUG__ not defined

10

If I compile

$gcc -D __DEBUG__ test.c

Output:

__DEBUG__ defined

30

Thus we can see how the C Preprocessors also help in deciding the course of action of a program. The above is also called Conditional Compilation

 

C: Ellipsis operator (…) : printf

Ever imagined how printf works, even though we are able to pass a number of arguments to it. If we design a function which takes two arguments and pass three parameters, we are bound to get this error “too many arguments to function”i.e., suppose we have a function
    int fun2(int a, int b)

and we call the function

    fun2(2,3,4)

we are sure to get the above error. So the question is how printf / scanf works with variable number of arguments? This is because C has a feature called ellipsis (…) by which you are able to pass variable number of arguments?

So the prototype of printf is

    int printf(const char *str,...)

But the next question is how then can we access the arguments in the function. This can be done by the power of pointers. Let’s take a pointer which points to the last argument before …
and depending on the next arguments of what we expect, we increment the pointer and increment it accordingly

Below is a simple code which shows how this can be done

int print(const char *str,...)

/*str has the number of integers passed*/

{

        int i;

        int num_count=atoi(str);

        int *num=(int *)&str;

        for(i=1;i<=num_count;i++)

                printf("%d ",*(num+i));}

int print_num(int num_count,...)

/*num_count contains the number of integers passed*/

{

        int i;

        int *num=&num_count;

        for(i=1;i<=num_count;i++)

                printf("%d ",*(num+i));

}

int main()

{

        print_num(3,2,3,4);

        print("3",2,3,4);

}

C: Structure Initialization (Advanced)


There is one more way by which we can initialize structures. These way utilizes the benefits of both the ways of structure initialization described here. That is we are able to initialize the elements of the structure using the set notation and also we need not remember the order of the elements of the structure.

Suppose consider the structure ‘student‘ we already used

struct student {

     int roll;

     int class;

     char name[50];

};

Now let’s declare a variable st3 and initialize using the third method

student st3={

           .name = "Mark", //Notice the equal to and the comma

           .class  = 10,

           .roll  = 1038

};

As you can see the way by which the variable st3 has been initialized. It has used the set notation and also see the order is not the same as in the case of the structure ‘student


The following program demonstrates this. Note the different ways by which the array of structures has been initialized

/*

*Different Ways of structure initialization

*/#include < stdio.h>

#include < string.h>

#define NAME_LEN 25

typedef unsigned short age_t;

typedef unsigned int roll_t;

typedef struct student{

    char name[NAME_LEN];

    roll_t rno;

    age_t age;

}student;

int main()

{

/* Method 3a: Just like the Method 2a, but here you do not

* need to know order of the elements in the declaration

*/

student st3={

.name = "Mark",//Notice the equal to and comma

.age  = 23,
.rno  = 1038
};

printf("%s %hi %u\n\n",st3.name,st3.age,st3.rno);

/*

* Method 3b: For Initializing an array of structures

*/

student st4[]={
{

.name = "Neil",

.age  = 23,

.rno  = 1039      },

{

.name = "Peter",

.age  = 23,

.rno  = 1040

}
};

printf("%s %hi %u\n%s %hi %u\n\n",st4[0].name,st4[0].age,

st4[0].rno, st4[1].name,st4[1].age,st4[1].rno);

/*

* Method 3c : Change the order of initialization of the

* elements of the array. Normally as seen in Method 2b,

* the 0th array element is initialized  then 1st, then

* 2nd and so on. So by using a variation  of Method 3b,

* we  can initialize the array elements in any order

*/

student st5[5]={

  [3]={

              .name = "Titus",

              .age  = 22,

              .rno  = 1041      },

[2]={

              .name = "Stephen",

              .age  = 23,

              .rno  = 1042

      }

      /*As you can see only 2nd and 3rd array elements has

       * been initialized and that too not in order. Such

       * an initialization is useful, if we wish to allocate

       * some fixed size array but only initialize some element

       */
};

printf("%s %hi %u\n%s %hi %u\n\n",st5[2].name,st5[2].age,

st5[2].rno, st5[3].name,st5[3].age,st5[3].rno);

}
The Methods 3a, 3b and 3c are the ways of structure initialization that I have seen in the kernel code. If you find any other way to do the structure initialization, kindly comment.

C: Structure Initialization

There are several ways by which a structure can be initialized. In the first way, we first declare the structure variable and initialize the fields of the structure with its name along with the variable name.
i.e., Suppose consider a structure ‘student

structure student {

   int roll;

   int class;

   char name[25];

};

Now we declare variable for the structure student st1
Now to initialize this variable, we access the elements of the structure using the variable
i.e.,

      st1.roll  = 21;

      strncpy (st1.name, "Albert", 10);

There can be case in which we do not initialize some elements of the structure, like in the above case, we did not initialize the element class for the variable st1. This can be considered as a big disadvantage. Because we may forget initializing some fields.

In the second way, we initialize the structure elements using the set notation.
like the variable st2 can be initialized as

     struct student st2 = {22, 10, "Alan"};

Unlike the first way, where we can initialize the elements of the structure in any order, here we must remember the order of the elements in the structure. But chances of not initializing a particular element is very less.

The following program demonstrates these two ways of structure initialization. Also check the way an array of structures is initialized.

/*Different Ways of structure initialization*/#include &lt;stdio.h>

#include &lt;string.h>

#define NAME_LEN 25

typedef unsigned short age_t;

typedef unsigned int roll_t;

typedef struct student{

char name[NAME_LEN];

roll_t rno;

age_t age;

}student;

int main()

{

/*

* Method 1a:Commonly seen initialization of a structure
    */student st;

strcpy

    (st.name,”Albert”); st.age=23; st.

rno

    =1034;
printf("%s %hi %u\n\n",st.name,st.age,st.rno);

/*

* Method 1b: For initialing an array of structures

*Commonly seen initialization of a structure

*/
    student st1 [2];

strcpy

    (st1[0].name,”Albert”);st1[0].age=23; st1[0].

rno

    =1034;
strcpy(st1[1].name,"Alvin");

st1[1].age=24;

st1[1].rno=1035;

printf("%s %hi %u\n%s %hi %u\n\n",st1[0].name,st1[0].age,

st1[0].rno,st1[1].name,st1[1].age,st1[1].rno);

/*

* Method 2a:Initializing like a set, the only requirement is

* that the order by which these elements are entered

* should be as in the declaration

*/
    student st2={“Alvin”,1035,22};

printf

    (“%s %hi %u\n\n”,st2.name,st2.age,st2.rno);
/*

* Method 2b: For Initializing an array of structures

*/
    student st2b[2]={ {“Alan”,1036,23}, {“Eric”,1037,22}};
printf("%s %hi %u\n%s %hi %u\n\n",st2b[0].name,st2b[0].age,

st2b[0].rno, st2b[1].name,st2b[1].age,st2b[1].rno);

}