Using Qualifiers for Pointers

This section provides some examples for the use of const or volatile, commonly used qualifiers in Embedded Programming.

Consider the following example:

  int i;

  

  const int ci;

  

The above definitions are: a normal variable i and a constant variable ci. The Compiler places each into ROM. Note that for C++, you must initialize the constant ci.

  int *ip;

  
  const int *cip;

  

In this case, ip is a pointer to an int, and cip is a pointer to a const int.

  int *const icp;

  
  const int *const cicp;

  

Here, icp is a const pointer to an int, where cicp is a const pointer to a const int.

The qualifier for such pointers always appears on the right side of the *.

You can express this rule in the same way for the volatile qualifier. Consider the following example of an array of five constant pointers to volatile integers:

  volatile int *const arr[5];

  

The array arr contains five constant pointers pointing to volatile integers. Because the array itself is constant, it is put into ROM. Whether the array is constant or not does not change where the pointers point. Consider the next example:

  const char *const *buf[] = {&a, &b};

  

Initializing buf makes it a non-constant array. This array contains two pointers which point to constant characters. Because the array is non-constant, neither the Compiler nor the Linker can place buf into ROM.

Consider a constant array of five ordinary function pointers:

  void (*fp)(void);

  

This shows a function pointer fp returning void and having void as parameter. Define the pointer with:

  void (*fparr[5])(void);

  

You can also use a typedef to separate the function pointer type and the array:

  typedef void (*Func)(void);

  
  Func fp;

  
  Func fparr[5];

  

You can write a constant function pointer as:

  void (*const cfp) (void);

  

Consider a constant function pointer having a constant int pointer as a parameter returning void:

  void (*const cfp2) (int *const);

  

Or a const function pointer returning a pointer to a volatile double having two constant integers as parameter:

  volatile double *(*const fp3) (const int, const int);

  

And one more:

  void (*const fp[3])(void);

  

This is an array of three constant function pointers, having void as parameter and returning void. The Compiler allocates fp in ROM because the fp array is constant.

Consider an example using function pointers:

  int (* (** func0(int (*f) (void))) (int (*) (void))) (int (*) 
  (void)) {

  
    return 0;

  
  }

  

This function, called func(), has one function pointer argument called f. The return value is a complex function pointer. Here, we do not explain where to put a const, so that the destination of the returned pointer cannot be modified. Alternately, write the same function more simply using typedefs (refer the following listing).

Listing: Using typedefs
typedef int (*funcType1) (void);
typedef int (* funcType2) (funcType1);

typedef funcType2 (* funcType3) (funcType1);

funcType3* func0(funcType1 f) {

  return 0;

}

In this case the places of the const become obvious. Just behind the * in funcType3:

  typedef funcType2 (* const constfuncType3) (funcType1);

  
  constfuncType3* func1(funcType1 f) {

  
    return 0;

  
  }

  

In the first version, place the const here:

  int (* (*const * func1(int (*f) (void))) (int (*) (void))) 

  
                                           (int (*) (void)) {

  
    return 0;

  
  }