Saturday, August 30, 2014

what is strict aliasing and pointer aliasing and use of restrict keyword


pointer aliasing:
  • Pointers alias when they point to the same address.
    • Writing via one pointer will change the value read through another.
  • The compiler often doesn’t know which pointers alias.
    • The compiler must assume that any write through a pointer may affect the value read from any another pointer!
    • So compiler will not optimize code to handle the memory correctly
Strict aliasing:
1
2
3
4
5
int foo(int *x, int *y) {
  *x = 0;
  *y = 1;
  return *x;
}
Generated code typically looks like this:
foo:    movl    $0, (%rdi)
        movl    $1, (%rsi)
        movl    (%rdi), %eax
        ret

1
2
3
4
5
int foo(int *x, long *y) {
=====> int and long pointer and so optimized
  *x = 0;
  *y = 1;
  return *x;
}
Since a pointer-to-int and a pointer-to-long may be assumed to not alias each other, the function can be compiled to return zero:

foo2:   movl    $0, (%rdi)
        xorl    %eax, %eax
        movq    $1, (%rsi)
        ret

http://www.davespace.co.uk/arm/efficient-c-for-arm/aliasing.html
http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html


restrcit:

Listing 2.1: Example of using the restrict-Keyword
1 int * aPtr ;
2 int * restrict aPtr ;


without restrict:
=================

1 void update (int *a , int *b , int * c )
2 {
3 * a += * c;
4 * b += * c;
5 }


Listing 2.3: The assembler-code to listing 2.2      (6 instructions as variable "c" loaded every time due to strict aliasing rule of c )
=================================================

1 update :
2 movl (% rdx ) , % eax
3 addl % eax , (% rdi )
4 movl (% rdx ) , % eax
5 addl % eax , (% rsi )
6 ret



void update_restrict (int *a , int *b , int * restrict c )
2 {
3 * a += * c;
4 * b += * c;
5 }


Listing 2.5: The assembler-code to listing 2.4 (only 5 instrcturions due to restrict keyword and variable "c" will not be loaded every time)
1 update_restrict :
2 movl (% rdx ) , % eax
3 addl % eax , (% rdi )
4 addl % eax , (% rsi )
5 ret


Bottom line:
=========
Due to strict alaising rules (i.e. 3 different pointers of same data type may have hold same variable's adddress in 3 pointer variable(in above example). so compiler every time will load the variable C from memory before perfomring the operations. so addtional load instruction is done in the assembly level

if we are sure that for the third variable always be unique memory then with the help of restrict keyword we can tell compiler to optimize the code. i.e no need of two load command. only one load command is sufficent.

Best reference:
https://wr.informatik.uni-hamburg.de/_media/teaching/wintersemester_2013_2014/epc-1314-fasselt-c-keywords-report.pdf


http://en.wikipedia.org/wiki/Restrict
http://www.lysator.liu.se/c/restrict.html
http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule
http://stackoverflow.com/questions/12255686/understanding-restrict-qualifier-by-examples

According to the C language rationale document, the aliasing rules were originally made to avoid forcing compilers to always make worst-case aliasing assumptions. With the addition of the “restrict” keyword, we have a superior solution for this problem and the aliasing rules are no longer needed for that purpose.
http://blog.regehr.org/archives/959



variable length arugment list in c

keypoints

  • initialization of variable 
    • (va_list  <variable>)
  • like malloc or memset  
    • va_start(<variable>,<number>) 
  • like foreach  
    • va_arg(<variable>,<datatype>) inside loop
  • like memory free 
    • va_end(<variable>)

#include <stdio.h> #include <stdarg.h> double average(int num,...) { va_list valist; double sum = 0.0; int i; /* initialize valist for num number of arguments */ va_start(valist, num); /* access all the arguments assigned to valist */ for (i = 0; i < num; i++) { sum += va_arg(valist, int); } /* clean memory reserved for valist */ va_end(valist); return sum/num; } int main() { printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5)); printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15)); }

very best explanation for each call present here:

The standard header <stdarg.h> contains a set of macro definitions that define how to step through an argument list. The implementation of this header will vary from machine to machine, but the interface it presents is uniform.
  1. The type va_list is used to declare a variable that will refer to each argument in turn; in minimal_printf , this variable is called ap , for "argument pointer".
  2. The macro va_start initializes ap to point to the first unnamed argument. It must be called once before ap is used.
  3. There must be at least one named argument; the final named argument is used by va_start to get started.
  4. Each call of va_arg returns one argument and steps ap to the next; va_arg uses a type name to determine what type to return and how big a step to take.
  5. Finally, va_end does whatever cleanup is necessary. It must be called before the program returns.
Here is the implemetation of our minimal_printf() which gives us idea about both the original printf() and variable number of argument function.

https://www.hackerearth.com/practice/notes/know-our-printf-variable-number-of-arguments-to-a-function/

Easy printf implementaion:

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

void errmsg( const char* format, ... )
{
  va_list arglist;

  printf( "Error: " );
  va_start( arglist, format );
  vprintf( format, arglist );
  va_end( arglist );
}

int main( void )
{
  errmsg( "%s %d %s", "Failed", 100, "times" );
  return EXIT_SUCCESS;
}
Ref: https://stackoverflow.com/questions/5977326/call-printf-using-va-list

or

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

char ErrStr[128];
char Status[128];
int flag=1;

void Feeder( char *buff,...)
{
    va_list arglist;

    va_start(arglist,buff);

    //customized operations...
    if (flag<0)
        vsprintf(ErrStr,buff,arglist);
    else if (flag>=0)
        vsprintf(Status,buff,arglist);

    va_end(arglist);
}

int main()
{
    Feeder("Hello World %d %f %s\n",5,5.55,"55.55");
    if(Status[0])
        printf("Result: %s\n",Status);

    return 0;
}
Ref: http://cc.byexamples.com/2007/01/18/va-list-create-function-like-printf-2/

Full printf implementation:

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

void Myprintf(char *,...);     //Our printf function
char* convert(unsigned int, int);   //Convert integer number into octal, hex, etc.


int main() 
{ 
 Myprintf(" WWW.FIRMCODES.COM \n %d", 9); 
 
 return 0;
} 


void Myprintf(char* format,...) 
{ 
 char *traverse; 
 unsigned int i; 
 char *s; 
 
 //Module 1: Initializing Myprintf's arguments 
 va_list arg; 
 va_start(arg, format); 
 
 for(traverse = format; *traverse != '\0'; traverse++) 
 { 
  while( *traverse != '%' ) 
  { 
   putchar(*traverse);
   traverse++; 
  } 
  
  traverse++; 
  
  //Module 2: Fetching and executing arguments
  switch(*traverse) 
  { 
   case 'c' : i = va_arg(arg,int);  //Fetch char argument
      putchar(i);
      break; 
      
   case 'd' : i = va_arg(arg,int);   //Fetch Decimal/Integer argument
      if(i<0) 
      { 
       i = -i;
       putchar('-'); 
      } 
      puts(convert(i,10));
      break; 
      
   case 'o': i = va_arg(arg,unsigned int); //Fetch Octal representation
      puts(convert(i,8));
      break; 
      
   case 's': s = va_arg(arg,char *);   //Fetch string
      puts(s); 
      break; 
      
   case 'x': i = va_arg(arg,unsigned int); //Fetch Hexadecimal representation
      puts(convert(i,16));
      break; 
  } 
 } 
 
 //Module 3: Closing argument list to necessary clean-up
 va_end(arg); 
} 

char *convert(unsigned int num, int base) 
{ 
 static char Representation[]= "0123456789ABCDEF";
 static char buffer[50]; 
 char *ptr; 
 
 ptr = &buffer[49]; 
 *ptr = '\0'; 
 
 do 
 { 
  *--ptr = Representation[num%base]; 
  num /= base; 
 }while(num != 0); 
 
 return(ptr); 
}
#include <stdio.h>
#include <stdarg.h>

extern char *itoa(int, char *, int);

void myprintf(const char *fmt, ...)
{
const char *p;
va_list argp;
int i;
char *s;
char fmtbuf[256];

va_start(argp, fmt);

for(p = fmt; *p != '\0'; p++)
 {
 if(*p != '%')
  {
  putchar(*p);
  continue;
  }

 switch(*++p)
  {
  case 'c':
   i = va_arg(argp, int);
   putchar(i);
   break;

  case 'd':
   i = va_arg(argp, int);
   s = itoa(i, fmtbuf, 10);
   fputs(s, stdout);
   break;

  case 's':
   s = va_arg(argp, char *);
   fputs(s, stdout);
   break;

  case 'x':
   i = va_arg(argp, int);
   s = itoa(i, fmtbuf, 16);
   fputs(s, stdout);
   break;

  case '%':
   putchar('%');
   break;
  }
 }

va_end(argp);
}



REf:
http://www.firmcodes.com/write-printf-function-c/
https://www.eskimo.com/~scs/cclass/int/sx11b.html

Used area:
  • To calculate average
  • in cli framework
Reference: