Monday, May 31, 2010

Storage class

In C, storage class gives two information about an object (variable or function).
  1. Scope of an object - gives information on visibility of a variable or function.
  2. Memory allocation - determines the part of memory where storage is allocated for an object and life of that object.
Storage class:
  • auto
  • extern
  • static
  • register
Automatic variable - Any variable defined inside a program block or nested block, by default, has automatic storage class. Scope of such variable is limited to the block where they are defined. These variables are also referred as local variable. These variables should be initialized unless the value is undefined.


External variable - These variables are also called global variable. These variables remain in life throughout the execution of a program. Memory allocated for every byte of extern variable is initialized to zero. The keyword extern can be omitted for a variable that has scope of file. But it is must if the variable is used across several source files. So usually, deceleration and definition is associated with such variables.


Static variable/function - In case of variables, static defines lifetime but for functions it defines scope. As for extern/global variable, static variables are initialized to zero. Automatic initialization can be overridden explicitly by programmer. However, the initializer must be a constant expression. Static variable defined inside a program block has the same scope as that of automatic variable but the storage allocation remains in existence until program terminates.


Register variable - A programmer may instruct the compiler to allocate a register in CPU for a variable. However, a register variable may or may not be allocated CPU register at runtime. This keyword gives flexibility to a programmer to control the efficiency of a program to some extent. Generally, variables which are accessed repeatedly or whose access time are critical may be declared to be of storage class register. Interestingly, this is the only storage class that can be defined for function parameter.

Some interesting observation.
  1. A register variable must have to be defined within a block or it can also be declared as a function parameter.
  2. In C, pointers cannot reference a register variable. But this allowed in C++.
    register int myVar = 0;int* myVarPtr = &myVar;  /* NOT allowed */
    
  3. Register storage class can not be defined for a global variable.
  4. A register variable has the same life and scope as that of automatic variable.
  5. These are vaild.
    register float myFlt;
    register char myChar;
    register int* myIntPtr;
    register double* myDobPtr;
    register float* myFltPtr;
    register char* myChrPtr;
    
  6. This is also valid.
    int main(register int argc, char* argv[])
    {
        ....
        ....
        return 0;
    }

How about these?
register int main(int argc, char* argv[])
{
   ....
   ....
   return 0;      
}
register int func1(int aa, char cc)
{
   ....
   ....
   return 0;      
}
int func2(int aa, char cc)
{
   static register int myInt = 0;
   ....
   return 0;      
}

C Questions

As a C programmer you would like to give some thought to following C question.

  1. Can structures be passed to the functions by value?
  2. Why cannot arrays be passed by values to functions?
  3. What are advantages and disadvantages of using macro and inline functions?
  4. What happens when recursion functions are declared inline?
  5. What is scope of static variables?
  6. What is the output of printf("\nab\bcd\ref"); C statement?
  7. #define cat(x,y) x##y concatenates x to y. But cat(cat(1,2),3) does not expand but gives preprocessor warning. Why?
  8. Is it possible to define a constant volatile variable? 
  9. Is it possible to define a volatile pointer?
  10. What does ++*ip increments?
  11. Describe an operation involving unsigned and signed.
  12. a+++b;
  13. Is this C statement valid? malloc(sizeof(0))
  14. main() {fork();fork();fork();printf("hello world"); }
  15. what is void (*fptr[10])()?
  16. Which way of writing infinite loops is more efficient than others?
  17. # error — what it does? 
  18. How is function itoa() written?
  19. How to know whether system uses big endian or little endian format and how to convert among them?
  20. What is forward reference w.r.t. pointers in c?
  21. How is generic list manipulation function written which accepts elements of any kind?
  22. How can you define a structure with bit field members?
  23. How do you write a function which takes 2 arguments - a byte and a field in the byte and returns the value of the field in that byte?
  24. What are the different storage classes in C?
  25. What are the different qualifiers in C?
  26. What is void pointer and what is its use?
  27. What is lvalue and rvalue?
  28. Using a variable define these -
    1. An integer
    2. A pointer to integer
    3. A pointer to a pointer integer
    4. An array of 10 integer
    5. An array of 10 pointer to integer
    6. A pointer to an array of 10 integer
    7. A pointer to a function that takes an integer as an argument and returns an integer
    8. An array of 10 pointer to function that take an integer and return an integer
  29. What do the following declarations mean?
    1. const int a;
    2. int const a;
    3. const int *a;
    4. int * const a;
    5. int const* a const;
  30. Is 3[myIntArr] = 5; valid where myIntArr is an array of 10 integers?

Monday, May 24, 2010

Const & Volatile

Const and Volatile are not opposite of each other!

Const - A variable whose value can not be changed, that is a constant. A programmer can not change the value of a variable declared as constant later in program. If it is not initialized at deceleration, it can not be assigned/initialized later.

An integer constant can be defined as:

const int myConst = 10;
int const myConst = 10;

Both the declaration have the same meaning. But in case of pointers, things are different.

const int *myPtr = (int *)0xFFFFFF04;     /* 1 */
int const *myPtr = (int *)0xFFFFFF05;     /* 2 */
int* const myPtr = (int *)0xFFFFFF06;     /* 3 */

Declaration 1 & 2 are the same and indicates the myPtr is an ordinary integer pointer and the integer pointed by it can not be modified. As a programmer, I can modify myPtr as:

int anInt = 10;
myPtr = &anInt;

But I can not do:

*myPtr = anInt;

However, the deceleration 3 defines a pointer myPtr that can not be modified but the value pointer by it can be modified.


Const, actually volatile also, variables are useful in real-time C programs. A const variable may never be initialized. An use case of this can be a the address of memory mapped I/O which is read only.

Volatile - Linux for you and Netrino articles have clearly explained volatile keyword. So, I will just be summarizing it here.

When a programmer declares a variable volatile, (s)he informs the compiler that the variable at any time during the life of program can change its value, so be careful while optimizing the code. In reference to the example of memory mapped I/O, I would define a pointer holding the address as a const variable but the value pointed by as volatile.

volatile int* const memIO = 0xFFFFFF05;

Some more declerations.

int volatile alcohol;
volatile int alcohol;            /* are the same - alcohol is volatile */

Now the pointer and volatile.

volatile int *myPtr;                    /* ordinary integer pointer to volatile integer data*/
int* volatile myPtr;                    /* volatile integer pointer to usual integer data*/
volatile int* volatile myPtr;       /* volatile integer pointer to volatile integer data*/ 


Now do NOT confuse in an interview.

Usage of volatile variable (as pointer in Netrino article)
  • Memory-mapped peripheral registers
  • Global variables modified by an interrupt service routine
  • Global variables accessed by multiple tasks within a multi-threaded application
What does volatile long * const timer = 0x0000ABCD mean?

Have fun!

Friday, May 21, 2010

Naming core dump file

Linux Kernel 2.6 provides user an option to name the core dump file. User can define template in file /proc/sys/kernel/core_pattern for naming the core dump file. The template contains % specifiers that get substituted when core dump file is generated.
  • %% a single % character
  • %p PID of dumped process
  • %u (numeric) real UID of dumped process
  • %g (numeric) real GID of dumped process
  • %s number of signal causing dump
  • %t time of dump, expressed as seconds since the Epoch (00:00h, 1 Jan 1970, UTC)
  • %h hostname (same as nodename returned by uname(2))
  • %e executable filename (without path prefix)
  • %c core file size soft resource limit of crashing process (since Linux 2.6.24)
Example:
I want my core dump filename look something like this signal-no_pid_exe-name_timestamp.core. On Ubuntu machine:

userOne@shangri-la:~/myTests/coredump$ su
root@shangri-la:/home/userOne/myTests/coredump# echo '%s_%p_%e_%t.core' > /proc/sys/kernel/core_pattern
root@shangri-la:/home/userOne/myTests/coredump# exit
userOne@shangri-la:~/myTests/coredump$ cat /proc/sys/kernel/core_pattern
%s_%p_%e_%t.core

After running the culprit program coredump, I got
11_12945_coredump_1274446084.core file.

Simple and nice!

Wednesday, May 12, 2010

Core dump

What is core dump?
Linux man page defines code dump as a disk file containing an image of process's memory at the time of termination. Core dump is result of some signals which causes a process to terminate and produce core dump file.

Signals:
  1. SIGQUIT - Quit from keyboard (Is this due to CLT-C?)
  2. SIGILL - Illegal instruction
  3. SIGABRT - Abort signal
  4. SIGFPE - Floating point exception
  5. SIGSEGV - Invalid memory reference
  6. SIGBUS - Bus error
There are several reasons in which core dump file is not produced (man core for details). But the most common reason is RLIMIT_CORE or RLIMIT_FSIZE is set to zero. ulimit command can be used to get/set the resource limit of shell.

ulimit -c unlimited

The above command will change the size of core dump file to unlimited.

By default the name of core dump file is "core". This can be configured in kernels 2.4.21 and beyond. A template can be defined in file /proc/sys/kernel/core_pattern to name the core dump file suitably.

Kernel 2.6.19 and onwards piping the core dump file to a program is possible. The file /proc/sys/kernel/core_pattern should contain pipe symbol "|" as its first character then the rest of the line is interpreted as program to be execute on core dump.

Kernel 2.6.23 and onwards lets the user to configure which memory segment are written on core dump file. The following bit mask should be defined in file /proc/PID/coredump_filter (0x3 is default value).

bit 0 Dump anonymous private mappings
bit 1 Dump anonymous shared mappings
bit 2 Dump file-backed private mappings
bit 3 Dump file-backed shared mappings

If a bit in the bit mask is set the corresponding memory is dumped.

Detailed explanation can be found in core dump man page.

Thursday, May 6, 2010

Data Types

Data types in C specifies two things:
  • How much of memory must be set aside for a variable.
  • How data represented by string of 1s & 0s are to be interpreted.

int, char, float and double are four data typed defined by C language. Size of memory allocated aside by compile for these data types differ from platform to platform. Data type qualifiers short and long overrides the memory related specification made by the data type on a variable. E.g. data type qualifier short preceding int asks compiler to set aside two bytes of memory on X86/Linux platform rather than four bytes. Signed and unsigned qualifiers overrides the interpretation that is dictated by data types.

Another data type in C is enum. Enum allows a programmer to define a variable which will take restricted range of values. Enum constants are automatically assigned integer values, starting with 0 and each successive constant incremented by 1. However, the values can be overridden as per programmer's requirement. The enum variables are treated as any other integer variable.

Is enum really required? I can do the same thing with #define, the macro. Yes agreed! But here are few differences.

  • Enum provides readability and maintainability to a program.
  • If a variable takes its value from a finite and pragmatically manageable range, errors (assignment of inappropriate value) can be easily avoided.
  • Addition and deletion of enumeration constants can be done without bothering about the numerical value (in contrast to that for macros).
  • Enum is substituted at compile time and #defines are substituted at preprocessing time.
  • Enum can have local to block scope as programmed but a #define has file-wide scope.