Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Wednesday, January 25, 2012

How to Debug C Program using gdb in 6 Simple Steps

Write a sample C program with errors for debugging purpose
To learn C program debugging, let us create the following C program that calculates and prints the factorial of a number. However this C program contains some errors in it for our debugging purpose.
$ vim factorial.c
# include 

int main()
{
	int i, num, j;
	printf ("Enter the number: ");
	scanf ("%d", &num );

	for (i=1; i
$ cc factorial.c

$ ./a.out
Enter the number: 3
The factorial of 3 is 12548672
Let us debug it while reviewing the most useful commands in gdb.

Step 1. Compile the C program with debugging option -g

Compile your C program with -g option. This allows the compiler to collect the debugging information.
$ cc -g factorial.c
Note: The above command creates a.out file which will be used for debugging as shown below.

Step 2. Launch gdb

Launch the C debugger (gdb) as shown below.
$ gdb a.out

Step 3. Set up a break point inside C program

Syntax:

break line_number
Other formats:
  • break [file_name]:line_number
  • break [file_name]:func_name
Places break point in the C program, where you suspect errors. While executing the program, the debugger will stop at the break point, and gives you the prompt to debug.
So before starting up the program, let us place the following break point in our program.
break 10
Breakpoint 1 at 0x804846f: file factorial.c, line 10.

Step 4. Execute the C program in gdb debugger

run [args]
You can start running the program using the run command in the gdb debugger. You can also give command line arguments to the program via run args. The example program we used here does not requires any command line arguments so let us give run, and start the program execution.
run
Starting program: /home/sathiyamoorthy/Debugging/c/a.out
Once you executed the C program, it would execute until the first break point, and give you the prompt for debugging.
Breakpoint 1, main () at factorial.c:10
10			j=j*i;
You can use various gdb commands to debug the C program as explained in the sections below.

Step 5. Printing the variable values inside gdb debugger

Syntax: print {variable}

Examples:
print i
print j
print num
(gdb) p i
$1 = 1
(gdb) p j
$2 = 3042592
(gdb) p num
$3 = 3
(gdb)
As you see above, in the factorial.c, we have not initialized the variable j. So, it gets garbage value resulting in a big numbers as factorial values.
Fix this issue by initializing variable j with 1, compile the C program and execute it again.
Even after this fix there seems to be some problem in the factorial.c program, as it still gives wrong factorial value.
So, place the break point in 10th line, and continue as explained in the next section.

Step 6. Continue, stepping over and in – gdb commands

There are three kind of gdb operations you can choose when the program stops at a break point. They are continuing until the next break point, stepping in, or stepping over the next program lines.
  • c or continue: Debugger will continue executing until the next break point.
  • n or next: Debugger will execute the next line as single instruction.
  • s or step: Same as next, but does not treats function as a single instruction, instead goes into the function and executes it line by line.
By continuing or stepping through you could have found that the issue is because we have not used the <= in the ‘for loop’ condition checking. So changing that from < to <= will solve the issue.

gdb command shortcuts

Use following shortcuts for most of the frequent gdb operations.
  • l – list
  • p – print
  • c – continue
  • s – step
  • ENTER: pressing enter key would execute the previously executed command again.

Miscellaneous gdb commands

  • l command: Use gdb command l or list to print the source code in the debug mode. Use l line-number to view a specific line number (or) l function to view a specific function.
  • bt: backtrack – Print backtrace of all stack frames, or innermost COUNT frames.
  • help – View help for a particular gdb topic — help TOPICNAME.
  • quit – Exit from the gdb debugger.

Monday, January 16, 2012

C Arrays Basics Explained with 13 Examples


This article is part of our on-going C programming series.
There are times while writing C code, you may want to store multiple items of same type as contiguous bytes in memory so that searching and sorting of items becomes easy. For example:
  1. Storing a string that contains series of characters. Like storing a name in memory.
  2. Storing multiple strings. Like storing multiple names.
C programming language provides the concept of arrays to help you with these scenarios.

1. What is an Array?

An array is a collection of same type of elements which are sheltered under a common name.
An array can be visualised as a row in a table, whose each successive block can be thought of as memory bytes containing one element. Look at the figure below :
An Array of four elements:
+===================================================+
| elem1     |  elem2      | elem3      | elem4      |
+===================================================+
The number of 8 bit bytes that each element occupies depends on the type of array. If type of array is ‘char’ then it means the array stores character elements. Since each character occupies one byte so elements of a character array occupy one byte each.

2. How to Define an Array?
An array is defined as following :
  [];
  • type-of-array: It is the type of elements that an array stores. If array stores character elements then type of array is ‘char’. If array stores integer elements then type of array is ‘int’. Besides these native types, if type of elements in array is structure objects then type of array becomes the structure.
  • name-of-array: This is the name that is given to array. It can be any string but it is usually suggested that some can of standard should be followed while naming arrays. At least the name should be in context with what is being stored in the array.
  • [number of elements]: This value in subscripts [] indicates the number of elements the array stores.
For example, an array of five characters can be defined as :
char arr[5];

3. How to Initialize an Array?

An array can be initialized in many ways as shown in the code-snippets below.
Initializing each element separately. For example :
int arr[10];
int i = 0;
for(i=0;i
Initializing array at the time of declaration. For example :
int arr[] = {'1','2','3','4','5'};
In the above example an array of five integers is declared. Note that since we are initializing at the time of declaration so there is no need to mention any value in the subscripts []. The size will automatically be calculated from the number of values. In this case, the size will be 5.
Initializing array with a string (Method 1):
Strings in C language are nothing but a series of characters followed by a null byte. So to store a string, we need an array of characters followed by a null byte. This makes the initialization of strings a bit different. Let us take a look :
Since strings are nothing but a series of characters so the array containing a string will be containing characters
char arr[] = {'c','o','d','e','\0'};
In the above declaration/initialization, we have initialized array with a series of character followed by a ‘\0′ (null) byte. The null byte is required as a terminating byte when string is read as a whole.
Initializing array with a string (Method 2):
char arr[] = "code";
Here we neither require to explicitly wrap single quotes around each character nor write a null character. The double quotes do the trick for us.

4. Accessing Values in an Array

Now we know how to declare and initialize an array. Lets understand, how to access array elements. An array element is accessed as :
int arr[10];
int i = 0;
for(i=0;i
As we can see above, the 5th element of array is accessed as ‘arr[5]‘.
Note that for an array declared as int arr[5]. The five values are represented as: arr[0] arr[1] arr[2] arr[3] arr[4] and not arr[1] arr[2] arr[3] arr[4] arr[5]
The first element of array always has a subscript of ’0′

5. Array of Structures

The following program gives a brief idea of how to declare, initialize and use array of structures.
#include

struct st{
    int a;
    char c;
}; 

int main()
{
    struct st st_arr[3]; // Declare an array of 3 structure objects 

    struct st st_obj0; // first structure object
    st_obj0.a = 0;
    st_obj0.c = 'a'; 

    struct st st_obj1; //Second structure object
    st_obj1.a = 1;
    st_obj1.c = 'b'; 

    struct st st_obj2; // Third structure object
    st_obj2.a = 2;
    st_obj2.c = 'c'; 

    st_arr[0] = st_obj0; // Initializing first element of array with first structure object
    st_arr[1] = st_obj1; // Initializing second element of array with second structure object
    st_arr[2] = st_obj2; // Initializing third element of array with third structure object 

    printf("\n First Element of array has values of a = [%d] and c = [%c]\n", st_arr[0].a, st_arr[0].c);
    printf("\n Second Element of array has values of a = [%d] and c = [%c]\n", st_arr[1].a, st_arr[1].c);
    printf("\n Third Element of array has values of a = [%d] and c = [%c]\n", st_arr[2].a, st_arr[2].c); 

    return 0;
}
The output of the above program comes out to be :
$ ./strucarr 

 First Element of array has values of a = [0] and c = [a] 

 Second Element of array has values of a = [1] and c = [b] 

 Third Element of array has values of a = [2] and c = [c]

6. Array of Char Pointers

The following program gives a brief Idea of how to declare an array of char pointers :
#include

int main()
{
    // Declaring/Initializing three characters pointers
    char *ptr1 = "Himanshu";
    char *ptr2 = "Arora";
    char *ptr3 = "TheGeekStuff"; 

    //Declaring an array of 3 char pointers
    char* arr[3]; 

    // Initializing the array with values
    arr[0] = ptr1;
    arr[1] = ptr2;
    arr[2] = ptr3; 

    //Printing the values stored in array
    printf("\n [%s]\n", arr[0]);
    printf("\n [%s]\n", arr[1]);
    printf("\n [%s]\n", arr[2]); 

    return 0;
}
The output of the above program is :
$ ./charptrarr 

 [Himanshu] 

 [Arora] 

 [TheGeekStuff]

7. Pointer to Arrays

Pointers in C Programming language is very powerful. Combining pointers with arrays can be very helpful in certain situations.
As to any kind of data type, we can have pointers to arrays also. A pointer to array is declared as :
 (*)[]
For example :
int(*ptr)[5];
The above example declares a pointer ptr to an array of 5 integers.
Lets look at a small program for demonstrating this :
#include

int main(void)
{
    char arr[3];
    char(*ptr)[3]; 

    arr[0] = 'a';
    arr[1] = 'b';
    arr[2] = 'c'; 

    ptr = &arr; 

    return 0;
}
In the above program, we declared and initialized an array ‘arr’ and then declared a pointer ‘ptr’ to an array of 3 characters. Then we initialized ptr with the address of array ‘arr’.

8. Static vs Dynamic Arrays

Static arrays are the ones that reside on stack. Like :
char arr[10];
Dynamic arrays is a popular name given to a series of bytes allocated on heap. this is achieved through malloc() function. Like :
char *ptr = (char*)malloc(10);
The above line allocates a memory of 10 bytes on heap and we have taken the starting address of this series of bytes in a character pointer ptr.
Static arrays are used when we know the amount of bytes in array at compile time while the dynamic array is used where we come to know about the size on run time.

9. Decomposing Array into Pointers

Internally, arrays aren’t treated specially, they are decomposed into pointers and operated there-on. For example an array like :
char arr[10];
When accessed like :
arr[4] = 'e';
is decomposed as :
*(arr + 4) = 'e'
So we see above that the same old pointers techniques are used while accessing array elements.

10. Character Arrays and Strings

Mostly new programmers get confused between character arrays and strings. Well, there is a very thin line between the two. This thin line only comprises of a null character ‘\0′ . If this is present after a series of characters in an array, then that array becomes a string. This is an array:
char arr[] = {'a', 'b', 'c'};
This is a string:
char arr[] = {'a', 'b', 'c', '\0'};
Note : A string can be printed through %s format specifier in printf() while an printing an array through %s specifier in printf() is a wrong practice.

11. Bi-dimensional and Multi-dimensional Arrays

The type of array we discussed until now is single dimensional arrays. As we see earlier, we can store a set of characters or a string in a single dimensional array. What if we want to store multiple strings in an array. Well, that wont be possible using single dimensional arrays. We need to use bi-dimensional arrays in this case. Something like :
char arr[5][10];
The above declaration can be thought of as 5 rows and 10 columns. Where each row may contain a different name and columns may limit the number of characters in the name. So we can store 5 different names with max length of 10 characters each. Similarly, what if we want to store different names and their corresponding addresses also. Well this requirement cannot be catered even by bi-dimensional arrays. In this case we need tri-dimensional (or multi-dimensional in general) arrays. So we need something like :
char arr[5][10][50];
So we can have 5 names with max capacity of 10 characters for names and 50 characters for corresponding addresses. Since this is an advanced topic, So we won’t go into practical details here.

12. A Simple C Program using Arrays

Consider this simple program that copies a string into an array and then changes one of its characters :
#include
#include

int main(void)
{
    char arr[4];// for accommodating 3 characters and one null '\0' byte.
    char *ptr = "abc"; //a string containing 'a', 'b', 'c', '\0' 

    memset(arr, '\0', sizeof(arr)); //reset all the bytes so that none of the byte contains any junk value
    strncpy(arr,ptr,sizeof("abc")); // Copy the string "abc" into the array arr 

    printf("\n %s \n",arr); //print the array as string 

    arr[0] = 'p'; // change the first character in the array 

    printf("\n %s \n",arr);//again print the array as string
    return 0;
}
I think the program is self explanatory as I have added plenty of comments. The output of the above program is :
$ ./array_pointer 

 abc 

 pbc
So we see that we successfully copied the string into array and then changed the first character in the array.

13. No Array Bound Check in a C Program

What is array bound check? Well this is the check for boundaries of array declared. For example :
char arr[5];
The above array ‘arr’ consumes 5 bytes on stack and through code we can access these bytes using :
arr[0], arr[1], arr[2], arr[3], arr[4]
Now, C provides open power to the programmer to write any index value in [] of an array. This is where we say that no array bound check is there in C. SO, misusing this power, we can access arr[-1] and also arr[6] or any other illegal location. Since these bytes are on stack, so by doing this we end up messing with other variables on stack. Consider the following example :
#include

unsigned int count = 1; 

int main(void)
{
    int b = 10;
    int a[3];
    a[0] = 1;
    a[1] = 2;
    a[2] = 3; 

    printf("\n b = %d \n",b);
    a[3] = 12;
    printf("\n b = %d \n",b); 

    return 0;
}
In the above example, we have declared an array of 3 integers but try to access the location arr[3] (which is illegal but doable in C) and change the value kept there.
But, we end up messing with the value of variable ‘b’. Cant believe it?, check the following output . We see that value of b changes from 10 to 12.
$ ./stk 

 b = 10 

 b = 12

Wednesday, October 12, 2011

Journey of a C Program to Linux Executable in 4 Stages


You write a C program, use gcc to compile it, and you get an executable. It is pretty simple. Right?
Have you ever wondered what happens during the compilation process and how the C program gets converted to an executable?
There are four main stages through which a source code passes in order to finally become an executable.

The four stages for a C program to become an executable are the following:
  1. Pre-processing
  2. Compilation
  3. Assembly
  4. Linking
In Part-I of this article series, we will discuss the steps that the gcc compiler goes through when a C program source code is compiled into an executable.
Before going any further, lets take a quick look on how to compile and run a ‘C’ code using gcc, using a simple hello world example.
$ vi print.c
#include 
#define STRING "Hello World"
int main(void)
{
/* Using a macro to print 'Hello World'*/
printf(STRING);
return 0;
}
Now, lets run gcc compiler over this source code to create the executable.
$ gcc -Wall print.c -o print
In the above command:
  • gcc – Invokes the GNU C compiler
  • -Wall – gcc flag that enables all warnings. -W stands for warning, and we are passing “all” to -W.
  • print.c – Input C program
  • -o print – Instruct C compiler to create the C executable as print. If you don’t specify -o, by default C compiler will create the executable with name a.out
Finally, execute print which will execute the C program and display hello world.
$ ./print
Hello World
Note: When you are working on a big project that contains several C program, use make utilityto manage your C program compilation as we discussed earlier.
Now that we have a basic idea about how gcc is used to convert a source code into binary, we’ll review the 4 stages a C program has to go through to become an executable.

1. PRE-PROCESSING

This is the very first stage through which a source code passes. In this stage the following tasks are done:
  1. Macro substitution
  2. Comments are stripped off
  3. Expansion of the included files
To understand preprocessing better, you can compile the above ‘print.c’ program using flag -E, which will print the preprocessed output to stdout.
$ gcc -Wall -E print.c
Even better, you can use flag ‘-save-temps’ as shown below. ‘-save-temps’ flag instructs compiler to store the temporary intermediate files used by the gcc compiler in the current directory.
$ gcc -Wall -save-temps print.c -o print
So when we compile the program print.c with -save-temps flag we get the following intermediate files in the current directory (along with the print executable)
$ ls
print.i
print.s
print.o
The preprocessed output is stored in the temporary file that has the extension .i (i.e ‘print.i’ in this example)
Now, lets open print.i file and view the content.
$ vi print.i
......
......
......
......
# 846 "/usr/include/stdio.h" 3 4
extern FILE *popen (__const char *__command, __const char *__modes) ;
extern int pclose (FILE *__stream);
extern char *ctermid (char *__s) __attribute__ ((__nothrow__));

# 886 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));

# 916 "/usr/include/stdio.h" 3 4
# 2 "print.c" 2

int main(void)
{
printf("Hello World");
return 0;
}
In the above output, you can see that the source file is now filled with lots and lots of information, but still at the end of it we can see the lines of code written by us. Lets analyze on these lines of code first.
  1. The first observation is that the argument to printf() now contains directly the string “Hello World” rather than the macro. In fact the macro definition and usage has completely disappeared. This proves the first task that all the macros are expanded in the preprocessing stage.
  2. The second observation is that the comment that we wrote in our original code is not there. This proves that all the comments are stripped off.
  3. The third observation is that beside the line ‘#include’ is missing and instead of that we see whole lot of code in its place. So its safe to conclude that stdio.h has been expanded and literally included in our source file. Hence we understand how the compiler is able to see the declaration of printf() function.
When I searched print.i file, I found, The function printf is declared as:
extern int printf (__const char *__restrict __format, ...);
The keyword ‘extern’ tells that the function printf() is not defined here. It is external to this file. We will later see how gcc gets to the definition of printf().
You can use gdb to debug your c programs. Now that we have a decent understanding on what happens during the preprocessing stage. let us move on to the next stage.

2. COMPILING

After the compiler is done with the pre-processor stage. The next step is to take print.i as input, compile it and produce an intermediate compiled output. The output file for this stage is ‘print.s’. The output present in print.s is assembly level instructions.
Open the print.s file in an editor and view the content.
$ vi print.s
.file "print.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $.LC0, %eax
movq %rax, %rdi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Though I am not much into assembly level programming but a quick look concludes that this assembly level output is in some form of instructions which the assembler can understand and convert it into machine level language.

3. ASSEMBLY

At this stage the print.s file is taken as an input and an intermediate file print.o is produced. This file is also known as the object file.
This file is produced by the assembler that understands and converts a ‘.s’ file with assembly instructions into a ‘.o’ object file which contains machine level instructions. At this stage only the existing code is converted into machine language, the function calls like printf() are not resolved.
Since the output of this stage is a machine level file (print.o). So we cannot view the content of it. If you still try to open the print.o and view it, you’ll see something that is totally not readable.
$ vi print.o
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@0^
^@UH<89>Ã¥¸^@^@^@^@H<89>ǸHello World^@^@GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3^@^
T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^H<90>^A^@^@^\^@^@]^@^@^@^@A^N^PC<86>^B^M^F
^@^@^@^@^@^@^@^@.symtab^@.strtab^@.shstrtab^@.rela.text^@.data^@.bss^@.rodata
^@.comment^@.note.GNU-stack^@.rela.eh_frame^@^@^@^@^@^@^@^@^@^@^@^
...
...
…
The only thing we can explain by looking at the print.o file is about the string ELF.
ELF stands for executable and linkable format.
This is a relatively new format for machine level object files and executable that are produced by gcc. Prior to this, a format known as a.out was used. ELF is said to be more sophisticated format than a.out (We might dig deeper into the ELF format in some other future article).
Note: If you compile your code without specifying the name of the output file, the output file produced has name ‘a.out’ but the format now have changed to ELF. It is just that the default executable file name remains the same.

4. LINKING

This is the final stage at which all the linking of function calls with their definitions are done. As discussed earlier, till this stage gcc doesn’t know about the definition of functions like printf(). Until the compiler knows exactly where all of these functions are implemented, it simply uses a place-holder for the function call. It is at this stage, the definition of printf() is resolved and the actual address of the function printf() is plugged in.
The linker comes into action at this stage and does this task.
The linker also does some extra work; it combines some extra code to our program that is required when the program starts and when the program ends. For example, there is code which is standard for setting up the running environment like passing command line arguments, passing environment variables to every program. Similarly some standard code that is required to return the return value of the program to the system.
The above tasks of the compiler can be verified by a small experiment. Since now we already know that the linker converts .o file (print.o) to an executable file (print).
So if we compare the file sizes of both the print.o and print file, we’ll see the difference.
$ size print.o
   text    data     bss     dec     hex filename
     97       0       0      97      61 print.o 

$ size print
   text    data     bss     dec     hex filename
   1181     520      16    1717     6b5 print
Through the size command we get a rough idea about how the size of the output file increases from an object file to an executable file. This is all because of that extra standard code that linker combines with our program.
Now you know what happens to a C program before it becomes an executable. You know about Preprocessing, Compiling, Assembly, and Linking stages There is lot more to the linking stage, which we will cover in our next article in this series.