Professional Documents
Culture Documents
1 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
20-11-2014 13:04
2 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
As for the second question, the answer is negative. Being able to refer to the same memory region through
different pointers, liberal use of casting in C makes it impossible for the allocator to figure out the contents
of the memory. What if this region initially had some other pointer in it and now seen as a collection of raw
bytes? So tracking down the pointer through memory to find unused regions and therefore garbage collection
becomes impossible.[2]
Contents
1 Module
1.1 Interface
1.2 Implementation
1.3 Test Program
2 Debugging a Program with GDB
2.1 Compiling Source Programs for Debugging
2.2 Major GDB Commands
2.2.1 Getting Help from GDB
2.2.2 Stopping Execution
2.2.3 Resuming Execution
2.2.4 Tracing a Running Program
2.2.5 Examining the Program
2.3 Debuggers with Graphical User Interface
3 Notes
Module
In this example, we provide an implementation for character strings as an opaque type. On top of the
previous presentation (Object-Based Programming), two levels of pointers in the representation of this type
present us with the chance to emphasize correct allocation and de-allocation orders.
Interface
String.h
1.
#ifndef STRING_H
2.
#define STRING_H
3.
4.
#define SUBSTR_NOT_FOUND -1
5.
20-11-2014 13:04
3 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
#define OUT_OF_MEMORY 2
Yet another forward declaration and its companion typedef! The former is used to forewarn the compiler
about the existence of the record type that we will be working on and the latter provides a handle on an
instance of such a record type. A type manipulated this way is called an opaque type; access to its instances
is mediated by a pointer.
Observe that all formal parameters provided in the prototypes are '[constant] pointers to struct _STR',
not 'struct _STR'. The reasoning for this is as follows: as a natural consequence of the information hiding
principle, we should keep the record type representation as an implementation detail: the user of a facility
need not concern herself about a detailed answer to the question "how" (implementation); she had better
concentrate on finding an answer to the question "what" (interface). This can be accomplished by giving her
things that do not change; things that may change should be made part of the implementation, not the
interface. And size of pointer to a record type remains the same although size of the record type itself may
change.
7.
struct _STR;
8.
typedef struct _STR *String;
9.
10.
extern String String_Create(const char*);
11.
extern void String_Destroy(String *this);
12.
extern int String_Compare(const String this, const String);
13.
extern String String_Concat(const String this, const String);
14.
extern int String_Contains(const String this, const String);
15.
extern int String_Containsr(const String this, const String);
16.
extern unsigned int String_Length(const String this);
17.
extern String String_Substring(const String this, unsigned int start, unsigned int length);
18.
extern char* String_Tocharp(const String this);
19.
20.
#endif
Implementation
20-11-2014 13:04
4 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
String.c
1.
#include <stddef.h>
2.
#include <stdio.h>
3.
#include <stdlib.h>
4.
#include <string.h>
5.
6.
#include "General.h"
7.
#include "utility/String.h"
In addition to the string [of characters] our representation provides the length of the string as a member field.
By doing this we trade space for time: when asked the length of a string, instead of going through all the
characters till we see the terminating NULL character, we return the value of this member field. In other
words, we prefer computation in space to computation in time.
9.
struct _STR {
10.
unsigned int length;
11.
char *str;
12.
};
13.
14.
static String String__Reverse(const String this);
15.
16.
String String_Create(const char* source) {
17.
String this;
18.
unsigned int i;
In addition to the static data area, where data that remain alive throughout the program execution reside, and
the runtime stack, where variables local to blocks live; we are provided with a pool of memory we can use
20-11-2014 13:04
5 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
during program execution. This memory region is called the programs free store or heap. Unlike the other
two areas, this area is managed by the programmer by means of dynamic memory management functions.
One aspect of free store memory is that it is unnamed. Objects allocated on the free store are manipulated
indirectly through pointers. A second aspect of the free store is that the allocated memory is un-initialized.
Allocation of memory at run time is referred to as dynamic memory allocation; memory allocated by means
of a function such as malloc is said to be allocated dynamically. However, this does not mean that storage for
the pointer itself is allocated dynamically. It might well be the case that it is allocated statically.[3]
Definition: An objects lifetimethat period of time during program execution when storage is bound to the
objectis referred to as an objects extent.
Variables defined at file scope are spoken of as having static extent. Storage is allocated before program
start-up and remains bound to the variable throughout program execution. Variables defined at local scope
are spoken of as having local extent. Storage is allocated on the run-time stack on entry to the local scope;
on exit, this storage is freed. A static local variable on the other hand exhibits static extent.
Objects allocated on the free store are spoken of as having dynamic extent. Storage allocated through the use
of functions like malloc in C remains bound to an object until explicitly deallocated by the programmer.
malloc returns a generic pointer, void*<>/source. Such a pointer cannot be
dereferenced with the <source lang="c" enclose="none">* or the subscripting
operators. In order to use this pointer to productive ends we must cast the returned value to some particular
pointer type. Assuming malloc can satisfy the request, local variable this contains an address value that
is to be interpreted to indicate the starting address of a struct _STR object. Otherwise, it contains a
polymorphic value, NULL, that signifies the failure of malloc.
Question:
Provided that the scheme presented in the Data-Level Structure chapter is used, what do you think is the
alignment required for the region allocated by malloc?
20.
this = (String) malloc(sizeof(struct _STR));
In case there may not be enough memory left in the heap, NULL will be returned by the malloc function.
We should let the user know about it.
Upon successful allocation of memory for the metadata, which is a combination of the pointer to the string
contents and its length, we must allocate room for the string contents. We do this by using the malloc
function for a second time. Eventually, if everything goes right, we have the figure given below.[4]
21.
if (this == NULL) {
22.
fprintf(stderr, "Out of memory...\n");
20-11-2014 13:04
6 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
23.
return(NULL);
24.
} /* end of if(this == NULL) */
25.
26.
this->length = strlen(source);
27.
this->str = (char *) malloc(this->length + 1);
28.
if (this->str == NULL) {
29.
free(this);
30.
fprintf(stderr, "Out of memory...\n");
31.
return(NULL);
32.
} /* end of if (this->str == NULL) */
Next loop and the two lines following it are used to copy a string of characters into another memory region.
We first, in the for loop, copy as many characters as the length of the string and then append the terminating
NULL character. Finally, now that we have moved the pointer in the process and it points to the NULL
character at the end of the string, we get it to point to the beginning of it using pointer arithmetic on the last
line.
Note that we could have done this using the standard string function strcpy. Along with strcpy, we are
given an assortment of string functions. In addition to these, since a string of characters is a memory region
ending with the sentinel value of \0, we can deal with such an entity using the appropriate memory
function. A partial list of such functions is provided below.
20-11-2014 13:04
7 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
Friends of strcpy
char* strcat(char
*dest, const char
*src)
char* strncat(char
*dest, const char
*src, size_t len)
char* strncpy(char
*dest, const char
*src, size_t len)
size_t strlen(const
char *s)
char* strchr(const
char* s, int c):
char* strrchr(const
char* s, int c):
char* strstr(const
char* str, const
char* sub):
int memcmp(const
void *ptr1, const
void *ptr2, size_t
len)
void* memcpy(void
*dest, const void
*src, size_t len)
void* memchr(const
void *ptr, int val,
size_t len )
34.
for (i = 0; i < this->length; i++)
20-11-2014 13:04
8 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
35.
*this->str++ = *source++;
36.
*this->str = '\0';
37.
this->str -= this->length;
38.
39.
return(this);
40.
} /* end of String String_Create(const char*) */
It is now time to release the area of memory pointed to by *this and return it to the free store for re-use. In
C, this can be done through a couple of functions, one of which is free.
Our destructor is admittedly very simple. It turns out that heap memory is the only resource used by the
String data type. It may not be the case for other data types. They may hold handles to resources like
files, semaphores, and so on.
Given the definition of struct _STR, we have the following memory layout:
*this is what is called a handle. The use of a pointer (struct _STR *), in other words indirection, is
needed to isolate the user from probable changes in the representation. Even when the implementer changes
the underlying representation, the user will not be affected.[5] Because she does not have direct access to the
representation. All she has is a handle on a String object, not the String object itself.
The region pointed to by a pointer should be deallocated only when everything pointed to by the pointers in
the region have been deallocated. Thats why we should first deallocate (*this)->str and then *this.
One thing to keep in mind: it is the region that is pointed by the pointer that gets freed, not the pointer itself!
By the time control reaches the return statement, we get the picture below. Shaded regions indicate memory
returned to the allocator; they may be re-used in subsequent allocation requests. For this reason, it is not
wise trying to use released memory.
Observe the signature of the destructor: The sole argument is of type String *, not String. This
modification is made to ensure that assignment of NULL to the handle of the deleted object is permanent.
The reason why we make this assignment in the destructor is to relieve user(s) of having to do it after the call
to the destructor, which issince there are many users who are concerned about what is provided by the
module and one implementer who should be concerned about how the module is implementedcertainly
more error prone.[6]
42.
void String_Destroy(String* this) {
43.
if (*this == NULL) return;
44.
20-11-2014 13:04
9 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
45.
free((*this)->str);
46.
(*this)->str = NULL;
47.
free(*this);
48.
49.
*this = NULL;
50.
} /* end of void String_Destroy(String*) */
51.
52.
int String_Compare(const String this, const String str2) {
53.
return(strcmp(this->str, str2->str));
54.
} /* end of int String_Compare(const String, const String) */
55.
56.
String String_Concat(const String this, const String str2) {
57.
String res_str;
58.
59.
res_str = (String) malloc(sizeof(struct _STR));
60.
if (!res_str) {
61.
fprintf(stderr, "Out of memory...\n");
62.
return(NULL);
63.
} /* end of if (!res_str) */
Our representation has two levels: one for the information about the underlying string and one for the string
itself. This means we need to issue two separate memory allocation commands, one for each level. So, at this
point in the program we have the memory layout given above. There are random values in the length and
str fields, which are probably left over from previous uses of the areas allocated to them.
64.
res_str->length = this->length + str2->length;
65.
res_str->str = (char *) malloc(res_str->length + 1);
20-11-2014 13:04
10 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
66.
67.
if (!res_str->str) {
68.
free(res_str);
69.
fprintf(stderr, "Out of memory...\n");
70.
return(NULL);
71.
} /* end of if (!res_str->str)*/
By the time control reaches this point we will have assigned the accurate value to the length field and
allocated enough memory to hold the concatenation of the two arguments. Note that content pointed to by
str is random. This doesnt mean that they cannot be used though. Application of strlen function on
str will still yield legitimate values, depending on where the first /0 appears in memory.
73.
while (*this->str) *res_str->str++ = *this->str++;
Finally we are over with copying the first argument into the resultant String. Well, almost! Each time we
copy a character from this->str into res_str->str, we advance the pointer so that it points to the
next character to be copied. By the time we reach the end of the source String (this->str), both
pointers will be greater than their original contents by as much as the length of the source string. As far as
res_str->str is concerned this is OK since a second string is yet to be appended to it. But the original
value of this->str is to be restored, which is done by the following compound assignment statement.
We could have done away with this readjustment had we used a temporary pointer to point to the same
location as this->str and copy the source String using this temporary pointer. The code for this is as
follows:
String String_Concat(const String this, const String str2) {
String res_str;
char* temp_str = this->str;
...
...
while (*temp_str) *res_str->str++ = *temp_str++;
...
...
} /* end of String String_Concat(const String, const String) */
20-11-2014 13:04
11 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
74.
this->str -= this->length;
75.
76.
while (*str2->str) *res_str->str++ = *str2->str++;
77.
str2->str -= str2->length;
78.
*res_str->str = '\0';
79.
res_str->str -= res_str->length;
80.
81.
return(res_str);
Having copied the argument Strings into the resultant String we now return to the caller. Note that we
return a pointer to some object that resides in heap. This gives us the opportunity to share the same object
among function calls, something that we wouldnt have had had we chosen to use an object that resides in
the run-time stack: An object in the run-time stack is accessible only in the function it is created and those
functions that are directly and indirectly called from this function.
This may lead us to think that returning a pointer to some object in the static data region or the frame of
main function is a safe course. As far as lifetime of the object is concerned thats right.[7] But we now face
the limitation imposed by the static nature of the allocation: Objects allocated in these regions cannot
dynamically change in size. Size of an object created in the static data region is fixed at compile-time while
an object created in the run-time stack must have its size fixed at the point its definition is elaborated. This
implies the only way of implementing dynamic data structures is through the use of heap memory.[8], [9]
82.
} /* end of String String_Concat(const String, const String) */
83.
84.
int String_Contains(const String this, const String substr) {
85.
int i;
86.
unsigned int j;
87.
88.
for(i = 0; i <= this->length - substr->length; i++) {
89.
for (j = 0; j < substr->length; j++)
20-11-2014 13:04
12 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
90.
if (substr->str[j] != this->str[i + j]) break;
91.
if (j == substr->length) return(i);
92.
} /* end of outer for loop */
93.
94.
return(SUBSTR_NOT_FOUND);
95.
} /* end of int String_Contains(const String, const String) */
96.
97.
int String_Containsr(const String this, const String substr) {
98.
String this_rv = String__Reverse(this);
99.
String sub_rv = String__Reverse(substr);
100.
int where;
101.
102.
if (this_rv == NULL || sub_rv == NULL) {
103.
fprintf(stderr, "Out of memory...\n");
104.
return(OUT_OF_MEMORY);
105.
} /* end of if (this_rv == NULL || sub_rv == NULL) */
Backward search can be formulated in terms of forward search. Thats exactly what we do here. We make a
forward search of the reversed substring in the reversed string and return a value depending on the result of
this search.
106.
where = String_Contains(this_rv, sub_rv);
107.
108.
String_Destroy(&sub_rv);
109.
String_Destroy(&this_rv);
110.
if (where >= 0) return(this->length - substr->length - where);
20-11-2014 13:04
13 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
111.
else return(SUBSTR_NOT_FOUND);
112.
} /* end of int String_Containsr(const String, const String) */
113.
114.
unsigned int String_Length(const String this) {
115.
return(this->length);
116.
} /* end of unsigned int String_Length(const String) */
117.
118.
String String_Substring(const String this, unsigned int start, unsigned int len) {
119.
String res_str;
120.
unsigned int i;
121.
122.
if (start >= this->length || len == 0) return(String_Create(""));
123.
if (start + len > this->length) len = this->length - start;
124.
res_str = (String) malloc(sizeof(struct _STR));
125.
if (res_str == NULL) {
126.
fprintf(stderr, "Out of memory...\n");
127.
return(NULL);
128.
} /* end of if (res_str == NULL) */
129.
res_str->str = (char *) malloc(len + 1);
130.
if (res_str->str == NULL) {
131.
free(res_str);
132.
fprintf(stderr, "Out of memory...\n");
133.
return(NULL);
134.
} /* end of if (res_str->str == NULL) */
135.
136.
for (i = 0; i < len; i++)
137.
res_str->str[i] = this->str[start + i];
138.
res_str->str[i] = '\0';
20-11-2014 13:04
14 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
139.
res_str->length = len;
140.
141.
return(res_str);
142.
} /* end of String String_Substring(const String, unsigned int, unsigned int) */
The following is what we call a user-defined conversion function: it converts from String to char*.
Unlike C++, where the compiler implicitly calls such functions, this conversion function must be explicitly
invoked by the programmer.
144.
char* String_Tocharp(const String this) {
145.
char *res_str = (char *) malloc(this->length + 1);
146.
if (!res_str) {
147.
fprintf(stderr, "Out of memory...\n");
148.
return(NULL);
149.
} /* end of if(!res_str) */
150.
strcpy(res_str, this->str);
151.
152.
return(res_str);
153.
} /* end of char* String_Tocharp(const String) */
154.
155.
static String String__Reverse(const String this) {
156.
String str_reverse;
157.
unsigned int i;
158.
159.
str_reverse = (String) malloc(sizeof(struct _STR));
160.
if (!str_reverse) {
161.
fprintf(stderr, "Out of memory...\n");
20-11-2014 13:04
15 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
162.
return(NULL);
163.
} /* end of if (!str_reverse) */
164.
str_reverse->str = (char *) malloc(this->length + 1);
165.
166.
if (!str_reverse->str) {
167.
free(str_reverse);
168.
fprintf(stderr, "Out of memory...\n");
169.
return(NULL);
170.
} /* end of if (!str_reverse) */
171.
str_reverse->length = this->length;
172.
173.
for (i = 0; i < this->length; i++)
174.
str_reverse->str[i] = this->str[this->length - 1 - i];
175.
str_reverse->str[this->length] = '\0';
176.
177.
return(str_reverse);
178.
} /* end of String String__Reverse(const String) */
Test Program
String_Test.c
1.
#include <stdio.h>
2.
#include <stdlib.h>
3.
4.
#include "General.h"
5.
#include "utility/String.h"
6.
20-11-2014 13:04
16 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
7.
int main(void) {
8.
char *sztmp;
9.
int loc;
10.
String first_name, last_name, name;
11.
String strtmp, strtmp2;
12.
13.
first_name = String_Create("Tevfik");
For printing the contents of a String variable, we convert it to a C-style character string and pass this to
the printf function. But we have to be careful about avoiding garbage creation. If we pass the return
value, a pointer to char, of String_Tocharp to printf without storing it in a variable, it will be lost by
the time printf returns. This will turn the memory region pointed to by this pointer into garbage.
Something we dont want! For this reason, we first assign the return value to some temporary variable and
then send it to the printf function. As soon as printf returns, region pointed to by the temporary
variable is freed using free.
14.
printf("First name: %s", (sztmp = String_Tocharp(first_name)));
15.
printf("\tLength: %d\n", String_Length(first_name));
16.
free(sztmp);
17.
18.
last_name = String_Create("Aktuglu");
19.
printf("Last name: %s", (sztmp = String_Tocharp(last_name)));
20.
printf("\tLength: %d\n", String_Length(last_name));
21.
free(sztmp);
22.
23.
printf("Forward search for u in the last name: ");
24.
loc = String_Contains(last_name, strtmp = String_Create("u"));
25.
if (loc
== SUBSTR_NOT_FOUND)
26.
printf("u not found...Sth wrong with the String_Contains function!!!\n");
20-11-2014 13:04
17 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
27.
else printf("u found at location %d\n", loc);
28.
String_Destroy(&strtmp);
29.
30.
printf("Backward search for u in the last name: ");
31.
loc = String_Containsr(last_name, strtmp = String_Create("u"));
32.
if (loc == SUBSTR_NOT_FOUND)
33.
printf("u not found...Sth wrong with the String_Containsr function!!!\n");
34.
else printf("u found at location %d\n", loc);
35.
String_Destroy(&strtmp);
36.
37.
name = String_Concat((strtmp = String_Concat(first_name, (strtmp2 = String_Create(" ")))), last_name
38.
String_Destroy(&strtmp); String_Destroy(&strtmp2);
39.
printf("Name: %s", (sztmp = String_Tocharp(name)));
40.
printf("\tLength: %d\n", String_Length(name));
41.
free(sztmp);
42.
43.
strtmp = String_Substring(name, 0, String_Length(first_name));
44.
printf("Comparing first name with the first %d characters of the name...",
String_Length(first_name
45.
if (String_Compare(first_name, strtmp) == 0) printf("Equal\n");
46.
else printf("Not equal\n");
47.
48.
String_Destroy(&strtmp); String_Destroy(&first_name);
49.
String_Destroy(&last_name); String_Destroy(&name);
50.
51.
exit(0);
52.
} /* end of int main(void) */
20-11-2014 13:04
18 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
gdb
GNU gdb 5.0
Copyright 2000 Free Software Foundation. Inc.
...
20-11-2014 13:04
19 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
20-11-2014 13:04
20 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
20-11-2014 13:04
21 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
debugging String_Test.exe,
rbreak .*Cont.* and rbreak Cont
are equivalent and will both set breakpoints at String_Contains and
String_Containsr
.
A watchpoint is a special breakpoint that stops your program when the value of an expression changes. This
relieves you from the burden of predicting places where such changes may occur. It comes in three flavors:
watch expr
Sets a watchpoint that will break whenever expr is written into by the program and its value
changes.
rwatch expr
Sets a watchpoint that will break whenever expr is read by the program.
awatch expr
Sets a watchpoint that will break whenever expr is accessed (read or written into) by the
program.
A catchpoint is another special breakpoint that stops your program when a certain kind of event occurs, such
as the throwing of a C++ exception or the loading of a library.
An unconditional breakpoint, be that a breakpoint, watchpoint, or catchpoint, can be turned into a
conditional one by means of the condition command.
condition breakpoint_num [expression]
Adds the expression as a condition for the breakpoint specified by breakpoint_num. If there is
no expression part, then any condition set for the breakpoint is removed. That is, it becomes an
ordinary unconditional breakpoint.
Here, breakpoint number is an index used to refer to a particular breakpoint. It can be found out by issuing
the info breakpoints</t> command.
One can give any breakpoint a series of commands to execute when the program stops due
to that breakpoint.
commands [breakpoint_num]
command1
command2
...
commandn
end
Missing breakpoint number will cause the commands to be attached to the last
breakpoint set (not encountered!). Following commands and breakpoint number
with end can easily accomplish removal of a command list from a breakpoint.
Effect of commands can be partially obtained by display command, which adds its argument expression to a
so-called automatic display list. All items in this list are printed each time the program is stopped.
20-11-2014 13:04
22 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
Having figured out the problem in our program we may want to remove a breakpoint. This can be done by
using clear and delete commands.
clear
Removes breakpoints set at the instruction about to be executed.
clear (function | filename:function)
Removes the breakpoint set at the entry of the function passed as the argument.
clear (line_num | filename:line_num)
Removes any breakpoint set at or within the code of the specified line.
delete [breakpoints] [list_of_breakpoints]
Removes the breakpoints passed as arguments. With no argument, it deletes all the breakpoints.
Instead of removing a breakpoint we may choose to ignore or disable it. Such a breakpoint will be present
but not effective, awaiting its revival.
ignore breakpoint_num ignore_count
Causes the breakpoint referred to by breakpoint_num to be bypassed ignore_count times.
disable [breakpoints] [list_of_breakpoints]
Causes the given breakpoints to be ignored till a relevant enable command. If no list is supplied,
all breakpoints are disabled.
enable [breakpoints] [list_of_breakpoints]
Activates the previously disabled list of breakpoints.
u<>enable [breakpoints] once list_of_breakpoints
Activates the given list of breakpoints for only once.
enable [breakpoints] delete list_of_breakpoints
Activates the given list of breakpoints to work once, and then die. GDB will delete any
breakpoint in the list as soon as the program stops there.
Resuming Execution
Once a program has been stopped, it can be resumed in different ways. Following is a list of such commands:
next [no_of_repetitions]
Continues to the next source line. If the current line to be executed contains a function call, it is
executed in one single step without going into it. In other words, it never increases the depth of
the run-time stack. Supplied argument tells GDB the number of times to execute the next
command.
step [no_of_repetitions]
Continues to the next source line. Unlike next, if the current line to be executed contains a
function call, a new stack frame will be inserted and control will flow into the very first
executable statement in the called function.
nexti [no_of_repetitions]
Executes the next machine instruction and returns to the debugger. If the next instruction is a
function call, it executes the entire function and then returns.
stepi [no_of_repetitions]
Executes the next machine instruction and returns to the debugger.
continue [ignore_counts]
Continues running the program up to the next breakpoint. When passed an argument, it is taken
20-11-2014 13:04
23 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
to mean the number of times the debugger will ignore the breakpoint set at the most recently
encountered location for ignore_count 1 times. So, continue is equivalent to continue 1.
until [location]
When passed an argument, until continues running the program either until the specified
location or end of the current function is reached. When used without an argument, location is
assumed be the current line. It is very useful for avoiding stepping through a loop.
finish
Continues running the current function to completion.
return [ret_value]
Returns immediately to the caller without executing the remaining statements in the calleethat
is, the current function. If its a value-returning function, ret_value is interpreted as the return
value of the callee.
call expr
Evaluates the expression passed as its only argument without changing the current location.
Note that side-effects due to evaluation is permanent.
jump (line_no | *address)
Resumes execution at line or address specified in the argument.
The diagram below shows the effect of these commands. A dashed line is used to indicate a change in state
where effect of the transition is achieved by visiting all the intermediate states. For example, finishing f1
means executing the remaining statements in f1 and then returning, which is suggested by the dashed line.
returning from f2, however, is shown by a straight line, meaning it skips all statements in f2 and returns
control to main.
20-11-2014 13:04
24 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
20-11-2014 13:04
25 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
20-11-2014 13:04
26 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
arguments.[16] If either of the arguments is missing, with , still present, this missing value is
figured out by the other argument.
In addition to listing parts of the source file you may want to see the value of a variable or evaluate an
expression.
print [/format] expression
Evaluates expression and prints the result using format. Format specification can be any one of
the following:
d Interpret the value as an integer and print in signed decimal.
u Interpret the value as an integer and print in unsigned decimal.
x Interpret the value as an integer and print in hexadecimal.
o Interpret the value as an integer and print in octal.
t Interpret the value as an integer and print in binary.
c Interpret the value as an integer and print it as a character constant.
a Treat the value as an address and print.
f Print as a floating value.
A missing format specification will have GDB use an appropriate type. inspect is a synonym of
this command.
Expressions can be formed according to the syntax rules of the source language. We can extend
this syntax using certain operators. @ treats parts of memory as an array; :: allows you to
specify the scope of an identifier. For example, given that seq is of int*,
print *sum_all::seq@10
sees the area of memory pointed to by seq, which is local to a function named sum_all, as an
array of size 10 and prints this array.
Each time an expression is evaluated and printed it is also saved in what is called value history. Values found
in this history can be referred to by prefixing its order of printing by the $ sign. First value to be printed is
$1; second value is $2 and so on. A single $ refers to the most recently printed value, and $$ refers to the
value before that. $$</rr>n refers to the nth value from the end. So, $$0 is equivalent to
$. One thing to keep in mind: value history holds values of expressions, not
expressions themselves. That is, given that *name holds "Mete" as its value, what gets
stored after printing *name in the value history is "Mete", not "*name".
Values in the value history can be inspected using the values subcommand of show.
show values [ n | + ]
Prints ten entries of value history centered on n. If no argument is passed, it prints the last ten
values. When supplied a + as the argument, this command prints ten history values just after the
values last printed.
If you do not want to record the result of the evaluation in the value history, you should use the x
commands.
x [[/repeat_count format unit] address]
Examines memory starting at address, independently of the underlying real data type. In
addition to those used in print, format can be s (for strings) or i (for machine instructions).
repeat_count and unit are used to determine how much memory to display: repeat_count * unit
bytes. repeat_count is a decimal value while unit can be one of the following:
20-11-2014 13:04
27 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
b Byte.
h Halfword (two bytes).
w Word (four bytes).
g Giant words (eight bytes).
Note that any one of the parameters might be missing. Format defaults to x initially and changes
each time you use either x or print. Repetition count defaults to 1. Unit size specified for a
particular value is accepted as a default next time same format is used.
When your program stops, you may want to know where it stopped and how it got there. This requires
information about the run-time stack, which are provided by the following commands. Note that these
commands do not change the control flow of the program. That is; issuing next after a combination of the
following commands will still continue execution from the most recently hit breakpoint. In other words, none
of the following commands modifies the instruction pointer.
frame [frame_no | address]
Moves you from one stack frame to another and prints information about the stack frame you
select. Stack frame can be selected by passing either the address or number of the frame.
frame_no is a non-negative number, where the currently executing frame is 0, its caller is 1, and
so on.
backtrace [[(- | +)] number_of_frames]
Prints a summary of how your program got where it is. When used with no argument, this
command prints a backtrace of the entire stack; with a positive number, it prints the innermost
(most recent) n stack frames; with a negative value passed as an argument, it prints the least
recent n stack frames. A synonym for this command is info stack.
up [n]
Moves n frames up the stack. That is, it moves toward less recently created frames. Default
value for n is 1.
down [n]
Moves n frames down the stack. In other words, it moves toward more recent stack frames.
In addition to these, we may get further information through the use of info subcommands.
info frame [address]
Prints a description of the frame without selecting it.
info args
Prints the arguments of the selected frame.
info locals
Prints the local variables of the selected frame.
info variables [reg_exp]
Displays all globals and static variable names used in the program. When passed an argument, it
displays all such information items matching the regular expression.
info scope (function_name | *address | line_num)
Lists the variables local to a scope. This listing includes the address of arguments and local
variables relative to frame base.
20-11-2014 13:04
28 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
If you are not in for the extra flexibility of the [incomplete!] command list presented in the previous section,
you may want to try one of the following debuggers, which basically put a graphical interface on top of
GDB.
Debugger
Description
rhide
This development environment can be used from within both DJGPP and
Cygwin. Typing rhide at the command prompt of either environment
will put you in a DOS window. Note that this is a complete IDE, which
happens to include a GDB-based debugger.
GNU
DDD
insight
kdbg
In addition to these, you can try GNU Emacs, XEmacs, Eclipse, KDevelop, NetBeans and MS Visual Studio,
which also offer integrated debugging support. One final thing you need to keep in mind: not all
debuggers/environments support all debugging formats. For instance, an executable containing GDB
debugging information will not make any sense to MS Visual Studio.
Notes
1. There is a rarely used option of invoking the garbage collector explicitly.
2. However, there are tools such as lint or splint, which can be satisfactorily used to this end.
3. As an example to pointers allocated statically consider the head of a list. As an example to pointers
allocated dynamically consider the next node link info in the same list. But whether the pointer is
allocated statically or dynamically and what it points to is in the static data area or run-rime stack, one
thing is certain: dynamically allocated memory is manipulated through pointers.
4. Note the argument passed to the String_Create function may point to memory in any one of the
three regions.
5. Presuming you use the underlying object through functions.
6. For an example to the latter method, see the Object-Based Programming chapter.
7. After all, the former has a static extent while the latter is allocated at entry to main and de-allocated
on exit, which is practically equivalent to the first case.
8. We can still simulate dynamic data structures by defining very large static data structures and using
this [static structure] as our heap. Indeed, this method is used to implement dynamic structures in
programming languages such as pre-90 FORTRAN and COBOL. Aside from its inability to provide
100% immunity from overflow, this approach is rather wasteful of memory.
9. Note that the figure does not reflect the C calling convention accurately. Since the area in the
run-time stack will be discarded by the caller, it is a bit premature to cross out the bottom half.
10. It should be noted this command and the next two are probably issued by two different parties:
implementer and user, respectively. Not forecasting the possibility of debugging or [more likely] not
willing to give away information about the implementation, implementer will probably not provide you
with debug versions of the object modules. In such a case, source-code level debugging of the program
is not a possibility when control flow is directed into one of the functions found in the module.
11. Core dump is the disk file containing the contents of random access memory at the point of crash,
which can later be used to figure out the cause of failure.
12. In our presentation, command abbreviations will be indicated by underlining parts of the relevant
command.
20-11-2014 13:04
29 of 29
http://en.wikibooks.org/wiki/Programming_Language_Concepts_Using...
13. Throughout the rest of this handout, we will underline part of the commands to express the shortest
possible prefix that stands for the command in question.
14. ( , ), [, ], | are metacharacters; they are not part of the syntax used to form the arguments passed to
the commands. ( and ) are used for grouping; [ and ] are used for expressing an option; | is used to
separate alternatives.
15. Offset value is added to the last line printed.
16. When used with offset values, second argument is added to the value obtained by adding the first
argument to the line to be printed.
Retrieved from "http://en.wikibooks.org
/w/index.php?title=Programming_Language_Concepts_Using_C_and_C%2B%2B
/Dynamic_Memory_Management&oldid=2710821"
20-11-2014 13:04