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

Sunday, July 22, 2012

Getting Started with Waf to Build C/C++ Applications

Waf is another build tool like SCons. It's a fork of SCons that is more Pythonic than SCons. Here is a simple example how to get build a C++ application with Waf.
waf-project
├── include
│   └── Hello.h
├── src
│   ├── Hello.cpp
│   └── Main.cpp
└── wscript
Hello.h
#ifndef HELLO_H_
#define HELLO_H_

class Hello {
public:
    void sayHello();
};


#endif /* HELLO_H_ */
Hello.cpp
#include <iostream>
#include "Hello.h"
using namespace std;

void Hello::sayHello() {
    cout << "Hello World" << endl;
}
Main.cpp
#include "Hello.h"
using namespace std;

int main() {
    Hello h;
    h.sayHello();

    return 0;
}

wscript
#!/usr/bin/env python

APPNAME = 'waf-project'
VERSION = '0.1'

top = '.' 
out = 'build'

def options(ctx):
    ctx.load('compiler_cxx')
    ctx.add_option("--shared", action="store_true", help="build shared library")
    ctx.add_option("--static", action="store_true", help="build static library")
    
def configure(ctx):
    ctx.load('compiler_cxx')

def build(ctx):
    if ctx.options.shared:
        ctx.shlib(source="src/Hello.cpp", target="hello", includes=["include"],
                  cxxflags="-g -Wall -O0")
    elif ctx.options.static:
        ctx.stlib(source="src/Hello.cpp", target="hello", includes=["include"],
                  cxxflags="-g -Wall -O0")
    else: # by default, build a shared library
        ctx.shlib(source="src/Hello.cpp", target="hello", includes=["include"],
                  cxxflags="-g -Wall -O0")
        
    ctx.program(source="src/Main.cpp", target="main", includes=["include"],
                use="hello")
waf configure
This will create all the configuration files in a "build" directory as specified in the out variable.
waf configure build --static
This will create a "hello" static library and a "main" program that is statically linked with the "hello" static library. The static library and the program will be created in a "build" directory as specified in the "out" variable.
waf configure build --shared
This will create a "hello" shared library and a "main" program that is dynamically linked with the "hello" shared library. The shared library and the program will be created in a "build" directory as specified in the "out" variable.

Wednesday, May 4, 2011

Getting Started with SCons to Build C/C++ Applications

SCons is a wonderful cross-platform build tool, mostly used for building C/C++ applications similar to make. It's based on Python and Python is an excellent programming language. Since Python is a fully-fledged programming language, there are many things that can be done easily in SCons as opposed to writing a shell script. In this blog, I'm going to show some basic stuff to get started with SCons.

SCons requires a file normally called SConstruct. The file structure in the below example looks like this.
scons-project
  |--- src/Hello.cpp
  |        Main.cpp
  |--- include/Hello.h
  |--- SConstruct

Hello.h
#ifndef HELLO_H_
#define HELLO_H_

class Hello {
public:
    Hello();
    virtual ~Hello();
    void sayHello() const;
};

#endif /* HELLO_H_ */

Hello.cpp
#include "Hello.h"
#include <iostream>
using namespace std;

Hello::Hello() {
}

Hello::~Hello() {
}

void Hello::sayHello() const {
    cout << "Hello!" << endl;
}

Main.cpp
#include "Hello.h"
#include <iostream>
using namespace std;

int main() {
    Hello hello;
    hello.sayHello();

#ifdef DEBUG
    cout << "Debugging..." << endl;
#endif
}

This is the simplest SConstruct file.
SConstruct
import os

env = Environment(CCFLAGS="-g -O0 -DDEBUG", CPPPATH="./include")

env.Program("bin/Main", ["src/Hello.cpp", "src/Main.cpp"])
This will produce an executable called Main. The CPPPATH here is to tell where the header files are located. And the CCFLAGS are the compiler flags used by the GCC compiler that tells the compiler to add the debug statement and turn off the optimization.

If we need to control how the object files are created, e.g. we want to put the object files in a directory called obj. We can use the Object node in our SConstruct. The SConstruct will look like this.
import os

env = Environment(CCFLAGS="-g -O0 -DDEBUG", CPPPATH="./include")

hello_obj = env.Object("obj/Hello", "src/Hello.cpp")
main_obj = env.Object("obj/Main", "src/Main.cpp")
env.Program("bin/Main", main_obj + hello_obj, LIBPATH="lib", LIBS="hello")

If we need to build a static library, i.e. libhello.a that can be linked against Main, we can modify the SConstruct to look this.
import os

env = Environment(CCFLAGS="-g -O0 -DDEBUG", CPPPATH="./include")

env.StaticLibrary("lib/hello", ["src/Hello.cpp"])
env.Program("bin/Main", ["src/Main.cpp"], LIBPATH="lib", LIBS="hello")

To build a shared library, i.e. libhello.so, we just need to change from StaticLibrary to SharedLibrary. The SConstruct will look like this.
import os

env = Environment(CCFLAGS="-g -O0 -DDEBUG", CPPPATH="./include")

env.SharedLibrary("lib/hello", ["src/Hello.cpp"])
env.Program("bin/Main", ["src/Main.cpp"], LIBPATH="lib", LIBS="hello")

Friday, February 25, 2011

Getting Started with GDB

GDB is a very powerful debugging tool for C/C++ and many other languages. Here I'm gonna show you how to get started with GDB.

testgdb.cpp
#include <iostream>
#include <string>
using namespace std;

string globalmsg = "Hello World";

void half(int& a) {
    a /= 2;
}

int whatever() {
    int i = 5;
    i *= 3;
    return i;
}

int main() {
    int a = 10;
    half(a);
    cout << a << endl;
    cout << whatever() << endl;
    return 0;
}

1. Compile the code
g++ -c -g -Wall -O0 testgdb.cpp
The -O0 flag is useful for debugging information because the compiler may do its own optimization that can eliminate some debugging information, such as -O2 flag for example.
2. Link it
g++ -o testgdb testgdb.o
3. Run it
gdb ./testgdb
After running this statement, there will be gdb prompt.
4. Set the breakpoint in line 18 and 19
break testgdb.cpp:18
break testgdb.cpp:19
5. See the list of breakpoints
info break
6. Remove the second breakpoint
delete 2
7. Run the program
run
8. See the current line
list
9. Step over to the next line
next
10. See the current line again
list
11. Step in to the half() function
step
12. Print the arguments
info args
13. Go to the next line
next
14. Print the value a now
print a
The new value should be 5.
15. Step out from half() function
finish
16. Print all the local variables
info locals
17. Set another breakpoint in line 13
break testgdb.cpp:13
18. Jump to that newly-set breakpoint
continue
19. Step over
next
20. Print the new value of i
print i
The value of i should be 15
21. Step out from the whatever() function
finish
22. Get the length of globalmessage string
print globalmessage.size()
23. Quit gdb
quit

I hope this brief introduction is useful. For more information, type
help <command>

Wednesday, January 5, 2011

Dealing with Unsigned Types in Java

Suppose we need to create a binary file with structure like this
1 unsigned byte
1 unsigned short
1 unsigned int

In C, we can do it easily like below.
writec.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* myfile;

    myfile = fopen("/tmp/writec.bin", "wb");
    if (!myfile)
    {
        printf("Unable to open the file!");
        return EXIT_FAILURE;
    }

    unsigned char x = 12;
    unsigned short y = 123;
    unsigned int z = 1234;
    fwrite(&x, sizeof(unsigned char), 1, myfile);
    fwrite(&y, sizeof(unsigned short), 1, myfile);
    fwrite(&z, sizeof(unsigned int), 1, myfile);

    fclose(myfile);

    return EXIT_SUCCESS;
}

To read such a file in Java can be quite tricky since the file has unsigned types. All data types in Java are signed, except for char. Here I'm gonna show you how to read such a file in Java.
ReadJava.java
package myproject;
 
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.nio.ByteOrder;
 
public class ReadJava {
 
    public static void main(String[] args) throws Exception {
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            fis = new FileInputStream("/tmp/writec.bin");
            bos = new ByteArrayOutputStream();
            byte[] bytes = new byte[128];
            int bytesRead;
            while ((bytesRead = fis.read(bytes, 0, bytes.length)) != -1) {
                bos.write(bytes, 0, bytesRead);
            }
            byte[] rawBytes = bos.toByteArray();
           
            int index = -1;
            int firstByte = 0;
            int secondByte = 0;
            int thirdByte = 0;
            int fourthByte = 0;
            short unsignedByte = 0;
            int unsignedShort = 0;
            long unsignedInt = 0;
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            unsignedByte = (short) ((firstByte) & 0xFF);
            System.out.println("unsigned byte=" + unsignedByte);
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            secondByte = (0x000000FF & ((int) rawBytes[++index]));
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                unsignedShort = (int) ((firstByte | secondByte << 8) & 0xFFFF);
            } else {
                unsignedShort = (int) ((firstByte << 8 | secondByte) & 0xFFFF);
            }
            System.out.println("unsigned short=" + unsignedShort);
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            secondByte = (0x000000FF & ((int) rawBytes[++index]));
            thirdByte = (0x000000FF & ((int) rawBytes[++index]));
            fourthByte = (0x000000FF & ((int) rawBytes[++index]));
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                unsignedInt = (long) (((firstByte | secondByte << 8 |
                    thirdByte << 16 | fourthByte << 24)) & 0xFFFFFFFFL);
            } else {
                unsignedInt = (long) (((firstByte << 24 | secondByte << 16 |
                    thirdByte << 8 | fourthByte)) & 0xFFFFFFFFL);
            }
            System.out.println("unsigned int=" + unsignedInt);
        } finally {
            if (bos != null) {
                bos.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
    }
}


Similarly, if we need to create such a file in Java, we can do the following.
WriteJava.java
package myproject;

import java.io.FileOutputStream;
import java.nio.ByteOrder;
 
public class WriteJava {
 
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("/tmp/writejava.bin");
       
        try {
            short unsignedByte = 0;
            int unsignedShort = 0;
            long unsignedInt = 0;
            int index = -1;
           
            byte[] rawBytes = new byte[7];
           
            unsignedByte = (short) (12 & 0XFF);
            rawBytes[++index] = (byte) ((unsignedByte & 0x00FF));
           
            unsignedShort = (int) (123 & 0XFFFF);
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                rawBytes[++index] = (byte) ((unsignedShort & 0x000000FF));
                rawBytes[++index] = (byte) ((unsignedShort & 0x0000FF00) >> 8);
            } else {
                rawBytes[++index] = (byte) ((unsignedShort & 0x0000FF00) >> 8);
                rawBytes[++index] = (byte) ((unsignedShort & 0x000000FF));
            }
           
            unsignedInt = (long) (1234 & 0xFFFFFFFFL);
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                rawBytes[++index] = (byte) ((unsignedInt & 0x000000FFL));
                rawBytes[++index] = (byte) ((unsignedInt & 0x0000FF00L) >> 8);
                rawBytes[++index] = (byte) ((unsignedInt & 0x00FF0000L) >> 16);
                rawBytes[++index] = (byte) ((unsignedInt & 0xFF000000L) >> 24);
            } else {
                rawBytes[++index] = (byte) ((unsignedInt & 0xFF000000L) >> 24);
                rawBytes[++index] = (byte) ((unsignedInt & 0x00FF0000L) >> 16);
                rawBytes[++index] = (byte) ((unsignedInt & 0x0000FF00L) >> 8);
                rawBytes[++index] = (byte) ((unsignedInt & 0x000000FFL));
            }
           
            fos.write(rawBytes);
        } finally {
            fos.close();
        }
    }
}

To read it in C, it's as easy as below.
readc.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* myfile;

    myfile = fopen("/tmp/writejava.bin", "rb");
    if (!myfile)
    {
        printf("Unable to open the file!");
        return EXIT_FAILURE;
    }

    unsigned char x;
    unsigned short y;
    unsigned int z;
    fread(&x, sizeof(unsigned char), 1, myfile);
    fread(&y, sizeof(unsigned short), 1, myfile);
    fread(&z, sizeof(unsigned int), 1, myfile);

    printf("unsigned byte=%d\n", x);
    printf("unsigned short=%d\n", y);
    printf("unsigned int=%d\n", z);

    fclose(myfile);

    return EXIT_SUCCESS;
}

Thursday, December 23, 2010

Creating Static and Shared Libraries using GCC

There are two types of libraries in C/C++:
1. Static libraries (.a on Linux or .lib on Windows): the library of object code that is linked with becomes part of the application.
2. Shared libraries (.so on Linux or .dll on Windows): the library of object code that is linked with does not become part of the application.

In this blog, I am going to show you how to create static and shared libraries using GCC on Linux. Although the the example shown below uses C++, but the same concept is applicable to C. Simply replace g++ with gcc.

Hello.h
#include <iostream>

class Hello
{
public:
    void sayHello() const;
}; 

Hello.cc
#include "Hello.h"
using namespace std;

void Hello::sayHello() const
{
    cout << "Hello World" << endl;
} 

Main.cc
#include "Hello.h"

int main()
{   
    Hello hello;
    hello.sayHello();

    return 0;
} 

To create a static library, do the following:
1. Compile the library code.
g++ -Wall -c Hello.c
This will produce Hello.o object file.
2. Create a static library.
ar -cvq libhello.a Hello.o
This will produce libhello.a static library.
3. Compile the Main.cc code and link it against the libhello.a static library.
g++ -o Main libhello.a Main.cc
This will produce the Main executable file. When you do ldd, you won't see the dependency to libhello library since it's a static library.
ldd Main
4. Execute the Main program.
./Main

To create a shared library, do the following:
1. Compile the library code.
g++ -Wall -fPIC -c Hello.c
This will produce Hello.o object file. The -fPIC flag is required for creating a shared library. See man g++ or man gcc for more information.
2. Create a shared library.
g++ -shared -o libhello.so Hello.o
This will produce libhello.so shared library.
3. Compile the Main.cc code and link it against the libhello.so shared library.
g++ -o Main libhello.so Main.cc
This will produce the Main executable file. When you do ldd, you will see the dependency to libhello library.
ldd Main
4. Execute the Main program.
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:."
./Main

Saturday, December 4, 2010

Getting Started with JNI

Java Native Interface (JNI) allows Java code to call native applications, e.g. applications written in C or C++. In this example, I will show you how to call C and C++ application from Java using JNI on Linux.

* JNI for C application *

CHelloWorld.java
public class CHelloWorld {
    
    static {
        System.loadLibrary("chello");
    }
    
    private native void print();

    public static void main(String[] args) {
        new CHelloWorld().print();
    }
}
1. Create a header file for CHelloWorld.
javah -jni CHelloWorld

2. Implement CHelloWorld.c
#include <jni.h>
#include <stdio.h>
#include "CHelloWorld.h"

JNIEXPORT void JNICALL
Java_CHelloWorld_print(JNIEnv *env, jobject obj)
{
    printf("Hello World from C\n");
    return;
}

3. Compile the CHelloWorld.c
gcc -Wall -fPIC -c CHelloWorld.c -I$HOME/jdk1.6.0_22/include \
-I$HOME/jdk1.6.0_22/include/linux
This will produce the CHelloWorld.o

4. Create a shared library (.so on Linux or .dll on Windows).
gcc -shared -o libchello.so CHelloWorld.o

5. Execute CHelloWorld in Java.
java -Djava.library.path=. CHelloWorld
The -Djava.library.path is required to tell where to load the library from. Alternatively, LD_LIBRARY_PATH (on Linux) or PATH (on Windows) can also be used.

* JNI for C++ application *
public class CppHelloWorld {

    static {
        System.loadLibrary("cpphello");
    }
    
    private native void print();

    public static void main(String[] args) {
        new CppHelloWorld().print();
    }
}
1. Create a header file for CppHelloWorld
javah -jni CppHelloWorld

2. Implement CppHelloWorld.cpp
#include <jni.h>
#include "CppHelloWorld.h"
#include <iostream>
using namespace std;

JNIEXPORT void JNICALL
Java_CppHelloWorld_print(JNIEnv *env, jobject obj)
{
    cout << "Hello World from C++" << endl;
    return;
}

3. Compile CppHelloWorld
g++ -Wall -fPIC -c CppHelloWorld.cpp -I$HOME/jdk1.6.0_22/include \
-I$HOME/jdk1.6.0_22/include/linux
This will produce the CppHelloWorld.o

4. Create a shared library (.so on Linux or .dll on Windows)
g++ -shared -o libcpphello.so CppHelloWorld.o

5. Execute CppHelloWorld in Java.
java -Djava.library.path=. CppHelloWorld
The -Djava.library.path is required to tell where to load the library from. Alternatively, LD_LIBRARY_PATH (on Linux) or PATH (on Windows) can also be used.

To call native library in Java using similar concept like Python's ctypes or C#'s P/Invoke, JNA is a good alternative.

Wednesday, December 1, 2010

Introduction to Makefile

Following the example from the previous blog on the Introduction to GCC, I am going to show you how to makefile to simplify all those steps.

If for example, we have a directory structure like this.
/home/cpp/HelloWorld.cpp
         /HelloWorld.hpp
         /Main.cpp

* Makefile *
CC=g++
CFLAGS=-Wall
OBJ=Main.o HelloWorld.o

Main: $(OBJ)

clean:
    rm -rf Main *.o

1. To build
make
2. To clean
make clean
Here we use Makefile's implicit rules by only specifying the CC and CFLAGS implicit variables. For more information, see this link.

If now, we have a directory structure like this.
/home/cpp/lib/libhello.a
         /include/HelloWorld.hpp
         /Main.cpp
* Makefile *
CC=g++
INCLUDEDIR=include
LIBDIR=lib/libhello.a
CFLAGS=-Wall -I$(INCLUDEDIR)
OBJ=Main.o
DEPS=$(INCLUDEDIR)/HelloWorld.hpp

Main: $(OBJ)
    $(CC) -o Main $(OBJ) $(LIBDIR) $(CFLAGS) 

%.o: %.cpp $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

clean:
    rm -rf Main *.o
For more information about the automatic variables, such as $@, $<, see this link.

Introduction to GCC

In this blog, I am going show you the basic stuff on how to compile, link, and create an executable of a C++ application using GCC. Although the example here uses C++, it should also be applicable to C by changing the compiler to use gcc instead of g++.

HelloWorld.hpp
#include <iostream>
using namespace std;

class HelloWorld
{
public:
    void sayHello() const;    
};

HelloWorld.cpp
#include "HelloWorld.hpp"

void HelloWorld::sayHello() const 
{
    cout << "Hello World" << endl;
}

Main.cpp
#include "HelloWorld.hpp"

int main()
{
    HelloWorld helloWorld;
    helloWorld.sayHello();        

    return 0;
}

If for example, we have a directory structure is as below.
/home/cpp/HelloWorld.cpp
         /HelloWorld.hpp
         /Main.cpp

In order to create a Main executable, we need to perform the following steps.
1. Compile the HelloWorld.cpp
g++ -Wall -c HelloWorld.cpp
-Wall option is used to display all the warnings. This will produce HelloWorld.o object file.
2. Compile the Main.cpp
g++ -Wall -c Main.cpp
This will produce Main.o object file.
3. Link the two object files (HelloWorld.o and Main.o) to create an executable (Main).
g++ -Wall -o Main Main.o HelloWorld.o
This will produce Main executable file.
4. Execute the Main file.
./Main

If we change the directory structure as below.
/home/cpp/HelloWorld.cpp
         /include/HelloWorld.hpp
         /Main.cpp
We will need to perform the following steps.
1. Compile the HelloWorld.cpp
g++ -Wall -c -Iinclude HelloWorld.cpp
The -Iinclude is used here to tell the that header files are located in the ./include directory since HelloWorld.cpp requires HelloWorld.hpp (see the source file of HelloWorld.cpp). This step will produce HelloWorld.o object file.
2. Compile the Main.cpp
g++ -Wall -c -Iinclude Main.cpp
The -Iinclude is used here to tell that the header files are located in the ./include directory since Main.cpp requires HelloWorld.hpp (see the source file of Main.cpp). This step will produce Main.o object file.
3. Link the two object files (HelloWorld.o and Main.o) to create an executable (Main).
g++ -Wall -o Main Main.o HelloWorld.o
This will produce Main executable file.
4. Execute the Main file.
./Main

To make things more complicated, let's change the directory structure as below.
/home/cpp/lib/HelloWorld.cpp
         /include/HelloWorld.hpp
         /Main.cpp
Before that, let's create a static library (libhello.a) in the lib directory.
1. Compile HelloWorld.cpp
cd lib
g++ -Wall -c HelloWorld.cpp -I../include
2. Create a static library (libhello.a).
ar -crv libhello.a HelloWorld.o
3. To view the content of the static library.
ar -t libhello.a

Now we the directory structure should look like this.
/home/cpp/lib/libhello.a
         /include/HelloWorld.hpp
         /Main.cpp

1. Compile Main.cpp
g++ -Wall -c Main.cpp -Iinclude 
This step will produce Main.o object file.
2. Link the library to create a Main executable file.
g++ -Wall -o Main Main.o lib/libhello.a -Iinclude
Alternatively, this statement can also be used.
g++ -Wall -o Main Main.o -Llib -lhello -Iinclude
Here, we don't tell where the libhello.a location explicitly. Instead, we tell where the library directory is by specifying the -Llib. This means that the library directory is located in the ./lib. The -l will strip the word lib. Thus, if we have libraries like below:
libhello.a ---> this will become -lhello
libabc.a ---> this will become -labc
libxyz.a ---> this will become -lxyz

3. Execute the Main file.
./Main

Monday, May 10, 2010

Slotted Aloha Simulation

Slotted Aloha is an improvement over the original Aloha, which introduced discrete timeslot. Below is the Slotted Aloha simulation that I wrote. I didn't consider any retransmission or backoff in this simulation.

The maximum throughput for Slotted Aloha is 36%. This can be computed using S = Ge^-G. With this simulation, you will roughly get your around 36% of maximum throughput. Due to the lack of randomness in generating the exponential random variable, you may not get exactly 36% for the maximum throughput. But I hope this code can give you a head start :)

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

#define DEF_NUM_ALLOCATED 1000;
#define SIM_DURATION 1000
#define SLOT_SIZE 1.0
#define G_MAX 6.0
#define G_STEP 0.1
#define RAND_UNIFORM (double) random() / (double) RAND_MAX

/*
 *==============================================================================
 * Global variables
 *==============================================================================
 */
int s_evt_n_elements = 0;
int s_evt_n_allocated = 0;
struct slot_event *s_evt_list = NULL;

int p_evt_n_elements = 0;
int p_evt_n_allocated = 0;
struct packet_event *p_evt_list = NULL;

double p_error = 0.0;
int p_error_flag = 0;

/*
 *==============================================================================
 * Structures and their functions
 *==============================================================================
 */
struct slot_event
{
    double time;
    int num_packets;
};

struct packet_event
{
    double time;
};

int slot_event_add(struct slot_event);
int packet_event_add(struct packet_event);

/*
 *==============================================================================
 * Simulation functions
 *==============================================================================
 */
void run_simulation(double);
double calc_exp_random_var(double);
double get_max_packet_evt_time();
void init_slot_event_list();
void check_for_collisions();
int calc_successful_tx();
void clear_all();

/*
 *==============================================================================
 * Utility functions
 *==============================================================================
 */
int validate_args(int, char **);
void print_usage();

/*
 * Slotted Aloha Simulation.
 */
int main(int argc, char **argv)
{
    int n;
    double g, s;

    if (validate_args(argc, argv) == 0)
    {
        print_usage();
        return 1;
    }
    
    if (argc == 2)
    {
        p_error_flag = 1;
        p_error = atof(argv[1]);
    }
    
    for (g = 0.1; g <= G_MAX; g += G_STEP)
    {
        clear_all();
        run_simulation(g);
        init_slot_event_list();
        check_for_collisions();
        n = calc_successful_tx();
        s = (double) n / (double) s_evt_n_elements;
        printf("%lf,%lf\n", g, s);
    }
    free(s_evt_list);
    free(p_evt_list);
    
    return (EXIT_SUCCESS);
}

int slot_event_add(struct slot_event evt)
{
    if (s_evt_n_elements == s_evt_n_allocated)
    {
        if (s_evt_n_allocated == 0)
        {
            s_evt_n_allocated = DEF_NUM_ALLOCATED;
        }
        else
        {
            s_evt_n_allocated *= 2;
        }

        void *tmp = realloc(s_evt_list, (s_evt_n_allocated *
            sizeof(struct slot_event)));
        if (!tmp)
        {
            fprintf(stderr, "ERROR: Couldn't realloc memory\n");
            return (-1);
        }
        s_evt_list = (struct slot_event*) tmp;
    }
    s_evt_list[s_evt_n_elements] = evt;
    s_evt_n_elements++;

    return s_evt_n_elements;
}

int packet_event_add(struct packet_event evt)
{
    if (p_evt_n_elements == p_evt_n_allocated)
    {
        if (p_evt_n_allocated == 0)
        {
            p_evt_n_allocated = DEF_NUM_ALLOCATED;
        }
        else
        {
            p_evt_n_allocated *= 2;
        }

        void *tmp = realloc(p_evt_list, (p_evt_n_allocated *
            sizeof(struct packet_event)));
        if (!tmp)
        {
            fprintf(stderr, "ERROR: Couldn't realloc memory\n");
            return (-1);
        }
        p_evt_list = (struct packet_event*) tmp;
    }
    p_evt_list[p_evt_n_elements] = evt;
    p_evt_n_elements++;

    return p_evt_n_elements;
}

/*
 * Run the simulation.
 */
void run_simulation(double lambda)
{
    int i;
    struct packet_event p_evt;
    double evt_time = 0.0;
    for (i = 0; i < SIM_DURATION; i++)
    {
        if (p_evt_n_elements > 0)
        {
            evt_time = p_evt_list[p_evt_n_elements-1].time;
        }
        p_evt.time = evt_time + calc_exp_random_var(lambda);
        packet_event_add(p_evt);
    }
}

/*
 * Calculate the exponential random variable based on a given lambda.
 */
double calc_exp_random_var(double lambda)
{
    return (-log(RAND_UNIFORM) / lambda);
}

/*
 * Get the max packet event time.
 */
double get_max_packet_evt_time()
{
    int i;
    double max_evt_time = p_evt_list[0].time;
    for (i = 1; i < p_evt_n_elements; i++)
    {
        if (p_evt_list[i].time > max_evt_time)
        {
            max_evt_time = p_evt_list[i].time;
        }
    }
    return max_evt_time;
}

/*
 * Initialize the slot event list.
 */
void init_slot_event_list()
{
    double slot_time;
    struct slot_event s_evt;
    double max_evt_time = get_max_packet_evt_time();
    for (slot_time = SLOT_SIZE; slot_time <= max_evt_time + SLOT_SIZE;
            slot_time += SLOT_SIZE)
    {
        s_evt.time = slot_time;
        s_evt.num_packets = 0;
        slot_event_add(s_evt);
    }
}

/*
 * Check for collisions.
 */
void check_for_collisions()
{
    int i, j;
    for (i = 0; i < s_evt_n_elements; i++)
    {
        for (j = 0; j < p_evt_n_elements; j++)
        {
            if (p_evt_list[j].time <= s_evt_list[i].time &&
                p_evt_list[j].time > (s_evt_list[i].time - SLOT_SIZE))
            {
                s_evt_list[i].num_packets += 1;
            }
        }
    }
}

/*
 * Calculate the sucessful transmission.
 */
int calc_successful_tx()
{
    int n = 0;
    int i;
    for (i = 0; i < s_evt_n_elements; i++)
    {
        if (s_evt_list[i].num_packets == 1)
        {
            if (p_error_flag == 1)
            {
                if (RAND_UNIFORM > p_error)
                {
                    ++n;
                }
            }
            else
            {
                ++n;
            }
        }
    }
    return n;
}

/*
 * Clear all the list.
 */
void clear_all()
{
    s_evt_list = NULL;
    p_evt_list = NULL;
    s_evt_n_elements = 0;
    p_evt_n_elements = 0;
    s_evt_n_allocated = 0;
    p_evt_n_allocated = 0;
}

/*
 * Validate arguments.
 */
int validate_args(int argc, char **argv)
{
    if (argc > 2)
    {
        return 0;
    }
    return 1;
}

/*
 * Print usage.
 */
void print_usage()
{
    fprintf(stderr, "Usage: slottedaloha [Perror]\n");
}