Creating a Linux Container in C++

I love Linux containers. You get a degree of separation from the host and other machines without hosting a full VM and without requiring a whole second OS.

What are containers?

A process or group of processes that are running on the same kernel as the host but in isolation via namespaces, cgroups and images

Why would you do this?

  • Share resources (3 web servers in containers on one physical server for example)
  • Less overhead and quicker to spin up than a VM
  • To experiment in Linux without modifying the host OS settings or filesystem
  • To run software or use libraries that cannot or shouldn’t be run on the host (Mismatched versions, tries to read data from your home folder, tries to mess around with other processes, spams syslog, tries to phone home or query the network, or talk to Linux kernel modules)
  • Consistent behaviour (Developers can run wildly different machines but develop within identical containers, consistent continuous integration, simulate end users’ machines for debugging)
  • Run a collection of containers that can talk to each other but can’t talk to the rest of the network (Local testing, integration testing, load testing, mess around with network configurations and firewall rules without endangering the host)
  • Run a collection of containers that can talk to each other but only one or two of them are public facing (LAMP stack, ELK stack, a cluster, etc.)
  • Set limits on memory usage and disk usage (Restrict resource heavy applications or test out of memory situations without killing the host)
  • Share folders and even whole Linux kernel modules from the host into the container.

Why wouldn’t you do this?

  • A VM or separate machine is generally a better approach if you have the resources
  • A VM can be more secure due to better isolation, not sharing a kernel for example
  • A VM can be more stable due to not sharing the kernel and kernel modules
  • Containers must be the same architecture as the host
  • Applications and libraries in a container have to be created for a version of the Linux kernel that is compatible with the host

Fair enough. How do containers work?

Namespaces, cgroups and images are set up to provide an environment for the container’s processes to run in.

  • Namespaces – Isolate the processes from the host, giving it it’s own filesystem, process tree, network, IPC, hostname, and users
  • Cgroups – Set limits for CPU usage, memory, disk and more for the container
  • Images – An image or folder containing the applications, libraries, and data that a container needs to run, for example cut down all the way up to fully featured distros: busybox, alpine, centos, ubuntu, etc. (Docker and LXC allow combining images via an overlay so you can get alpine + java + nifi for example which a smushed together into a single filesystem

Great. Now what?

What does this look like in code?
Here is my C++ rewrite of Lizzie Dixon’s excellent C container. It demonstrates setting the cgroups, creating the namespaces, mounting the busybox filesystem, and launching the child process.


NOTE: This is just a proof of concept, it doesn’t have basic, nice things like networking, package management, file system overlays, any sort of Dockerfile/makefile/recipe support, code reviews, testing, battle hardened development history, etc. It’s not Docker, it’s a proof of concept of the basics of how containers work that doesn’t hide everything away in the Go language and libraries or a “docker run” command.

Here is an example of it running:

root@laptop:~/cpp-container# BUSYBOX_VERSION=1.33.0
root@laptop:~/cpp-container# ./cpp-container -h myhostname -m $(realpath ./busybox-${BUSYBOX_VERSION}/) -u 0 -c /bin/sh
=> validating Linux version…4.3.0-36-generic on x86_64.
Starting container myhostname
=> setting cgroups…
memory…
cpu…
pids…
done.
=> setting rlimit…done.
=> remounting everything with MS_PRIVATE…remounted.
=> making a temp directory and a bind mount there…done.
=> pivoting root…done.
=> unmounting /oldroot.kCeIkg…done.
=> trying a user namespace…writing /proc/3856/uid_map…writing /proc/3856/gid_map…done.
=> switching to uid 0 / gid 0…done.
=> dropping capabilities…bounding…inheritable…done.
=> filtering syscalls…done.
/ # echo "Look ma, no docker"
Look ma, no docker
/ # whoami
root
/ # exit
Container myhostname has exited with return code 0
=> cleaning cgroups…done.
root@laptop:~/cpp-container#

Stop Watch and Time Out Classes

I have a passing interest in stop watch and time out type classes. Keeping track of elapsed time, remaining time. They are very basic classes, but I find them interesting.

GetTimeMS function

The stop watch and timer classes use this function to get the system time, we actually return the system time minus the application start time to get a time relative to the application start time, starting at 0. This is not necessary, return the system time is fine, returning the time the application is running is usually just easier to think about than the time since 1970, which is kind of arbitrary.
This function uses milliseconds, if this is not enough, we can easily switch to nanoseconds.

typedef uint64_t durationms_t;
 
// Get the time since epoch in milliseconds
durationms_t GetTimeMS()
{
  static const std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
 
  const std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  return std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
}

Stop watch class

Provides start, stop, reset and we can get the total duration.

class cStopWatch
{
public:
  cStopWatch();
 
  void Start();
  void Stop();
  void Reset();
 
  durationms_t GetTotalDurationMS() const;
 
private:
  bool running;
  durationms_t started;
  durationms_t totalDuration;
};
 
cStopWatch::cStopWatch() :
  running(false),
  started(0),
  totalDuration(0)
{
}
 
void cStopWatch::Start()
{
  assert(!running);
 
  // Started our stop watch
  started = GetTimeMS();
 
  running = true;
}
 
void cStopWatch::Stop()
{
  assert(running);
 
  // Get the time now
  const durationms_t now = GetTimeMS();
 
  // Add the duration for this period
  totalDuration += now - started;
 
  // Reset our start time
  started = 0;
 
  running = false;
}
 
void cStopWatch::Reset()
{
  started = 0;
  totalDuration = 0;
 
  running = false;
}
 
durationms_t cStopWatch::GetTotalDurationMS() const
{
  if (running) {
    // Get the time now
    const durationms_t now = GetTimeMS();
 
    // Return the previous duration plus the duration of the current period
    return totalDuration + (now - started);
  }
 
  return totalDuration;
}

Example usage

cStopWatch stopWatch;
 
// Start the stop watch
stopWatch.Start();
 
// Sleep for 1 second
const uint64_t timeout_ms = 1000;
::usleep(1000 * timeout_ms);
 
// Stop the stop watch
stopWatch.Stop();
 
// We have now waited for at least 1 second
std::cout<<"Stop watch time: "<<stopWatch.GetTotalDurationMS()<<" ms"<<std::endl;

Time out class

Allows us to get the time remaining, check if the time out has expired and reset the time out.

class cTimeOut {
public:
  explicit cTimeOut(durationms_t timeout);
 
  void Reset();
 
  bool IsExpired() const;
 
  durationms_t GetRemainingMS() const;
 
private:
  const durationms_t timeout;
  durationms_t startTime;
};
 
cTimeOut::cTimeOut(durationms_t _timeout) :
  timeout(_timeout),
  startTime(GetTimeMS())
{
}
 
void cTimeOut::Reset()
{
  startTime = GetTimeMS();
}
 
bool cTimeOut::IsExpired() const
{
  return ((GetTimeMS() - startTime) > timeout);
}
 
durationms_t cTimeOut::GetRemainingMS() const
{
  // Get the total time this timeout uhas been running for so far
  const int64_t duration = int64_t(GetTimeMS()) - int64_t(startTime);
 
  // Calculate the remaining time
  const int64_t remaining = (int64_t(timeout) - duration);
 
  // Return the remaining time if there is any left
  return (remaining >= 0) ? remaining : 0;
}

Example usage

// Create a 5 second time out
cTimeOut timeout(5000);
 
// Wait until the time out is expired
while (!timeout.IsExpired()) {
  std::cout<<"Waiting..."<<std::endl;
 
  // Sleep for 1 second
  const uint64_t timeout_ms = 1000;
  ::usleep(1000 * timeout_ms);
}
 
std::cout<<"Time out reached"<<std::endl;

Debugging 101

Tips to help you find bugs.

Turn the warning level up and turn on warnings as errors
I know, it can be a pain, but it works. It helps you produce more rhobust, forward compatible, portable code that is syntactically correct on more compilers.
Use assert …
Assert will help you find errors before you even knew there was a problem. It is 100x better if your application tells you exactly where problems are and breaks into the debugger than for your application to crash for the customer. It goes hand in hand with compile time type safety, compiler warnings and static_assert.
… and use if () return
Think of assert as flagging the problem for you to fix and if () return as guarding the application from crashing for the customer.
Print to your errors/trace file
It can be easier to read what the application did rather than stepping through it, in some cases it is not possible to step through the code at all; full screen games, embedded devices and drivers for example. Print out variables, function entrance/exit and “I am here” lines.
Simplify
Comment out or remove as much code as possible. Slowly remove lines until you find the offending line. Try different ways of doing the same thing. Read your errors/trace file. If I had a dollar for every time a coworker tells me there is a bug in the library/standard library/compiler/Operating System and it is actually an error in their code and they have ignored a printed error, I would buy a Ferrari, and then I would buy them a pair of spectacles and I would say, “Use these to read these”, and point at the error message.
Write data to files and validate your files
For example XML, HTML, JSON, RSS, KML, PNG, WAV and MP3, can all be written to files and run through third party validation software. You can even setup a unit test to write these to a file and run the validator for you.
Use your debugger
Put break points on suspect lines, step through functions, find out the value of variables, look at what each thread is doing, look at the call stack.
Read the documentation for the library you are using
You may be using a library incorrectly, it may have conditions or prerequisites you didn’t know about. If it is too complex wrap it into something easier to digest. If its usage is error prone wrap it into something simpler and type safe, that only uses what you need. An optimising compiler will factor out your wrapper and it will have no run time impact.
Use STL
It is there for a reason. Millions of developers have used it for almost two decades, hundreds of thousands of eyes have pored over the source code to it. Chances are that it is more capable, less bug ridden and more portable than your hodge podge collection of classes. A large percentage of bugs I have seen are in classes that could be replaced by the STL. Plus developers will “just know” what your code does because they already have experience with STL. Just use it.

Pimp My Code Part 2

Xhibit

char szPassword[255];
GenerateRandomPassword(szPassword, 8);
char szText[255];
sprintf(szText, "User: %s, ID: %d, Password: %s", szUser, int(userid++), szPassword);

Don’t increment and use a variable on the same line. We know, you’re very tricky, you saved a line. You also made sure that beginners to C++ don’t know what the result will be. Keep it simple stupid. Create the simplest most readable code possible, it makes skimming over code and debugging code much easier. Fixed length arrays are very prone to buffer overruns, in this example szPassword is probably only 8 characters long after calling GenerateRandomPassword, but szUser could be any length and could definitely overrun 255 characters. The best way to mitigate this problem is to use a real string class such as std::string. We can also avoid using sprintf by using a type safe string writing class, std::ostringstream. Code using std::ostringstream is also slightly more human readable.

userid++;
const std::string sPassword = GenerateRandomPassword(8);
std::ostringstream oText;
oText<<"User: "<<sUser<<", ID: "<<userid<<", Password: "<<sPassword;
std::string sText = oText.str();

There, type safe, buffer overflow safe, future proof and slightly more readable, what’s not to like?

Pimp My Code Part 1 Redux

Xhibit

Not exactly a redux, but very similar to last time:

bIsNotEmpty = false;
if (vNests.GetSize() != 0) {
  if (vNests[0]->vEggs.GetSize() != 0) bIsNotEmpty = true;
}

First of all we don’t actually care about the size, we just care that we have (Or don’t have) a nest with eggs in it. Depending on the container GetSize may or may not be a variable look up. IsEmpty is always a variable lookup:

bIsNotEmpty = false;
if (!vNests.IsEmpty()) {
  if (!vNests[0]->vEggs.IsEmpty()) bIsNotEmpty = true;
}

We can combine this into a single line:

bIsNotEmpty = (!vNests.IsEmpty() && !vNests[0]->vEggs.IsEmpty());

I would use more descriptive variable naming change my logic to use bIsEmpty/!bIsEmpty. Using bIsNot variables is often confusing and leads to harder to read code:

bIsNestWithEggs = (!vNests.IsEmpty() && !vNests[0]->vEggs.IsEmpty());
bIsEmpty = !bIsNestWithEggs;
// Use bIsEmpty and !bIsEmpty from now on

Pimp My Code Part 1

Xhibit

inline bool IsSpecial(const char* szValue)
{
 // Returns true if this is a special value
 if (stricmp(szValue, "MySpecialValue") == 0) {
   return true;
 }
 
 return false;
}

I see this sort of thing all the time. For boolean functions that call boolean functions the if and return statements are usually superflous, we can use the return value of (stricmp(szValue, “MySpecialValue”) == 0) itself:

// Returns true if this is a special value
inline bool IsSpecial(const char* szValue)
{
 return (stricmp(szValue, "MySpecialValue") == 0);
}

If it were up to me I would also use a string class and keep as much of the code as possible in the string “realm” (This makes the code a lot simpler and easier to read):

// Returns true if this is a special value
inline bool IsSpecial(const string& sValue)
{
 return (sValue == "MySpecialValue");
}

Java

I’ve been getting back into Java in my spare time recently, as I think about possibly making a few Android games. These are some notes about the differences between Java and C++.

  • In Java (almost) everything is an object. Strings, Floats and Ints are first class types.
  • In C++ we usually don’t have to stress too much about performance. We can usually afford to do extra processing, create and pass around as many temporaries as we like, use extra ram and hold onto large amounts of ram. Java dies if you use too many temporaries. Performance in Java is highly reliant on the algorithms used.
  • Java benefits from lazy initialisation, not doing anything you don’t need to until you need to.
  • Caching previous results (But not holding onto excessive amounts of ram).
  • Reducing number of temporaries by using classes such as StringBuilder.
  • Java is fun to use. Like a strict C++. Strict in a good way. It is how C++ should have been created. Unfortunately the C++ standards committee decided that backwards compatability was a higher priority than creating awesomeness.
  • The built in libraries are pretty good. I can still write algorithms quicker in C++ but there is a lot more extra functionality in the standard Java libraries such as regular expressions, file system, networking, threads, gui and sql. This is changing slightly with C++0x, but it still lacks basic things such as XML parsing, sql and anything related to gui.
  • Each file can only contain 1 public class. This enforces good structure on your API, “what is the public interface going to be?”, where in C++ a lot of APIs just throw all classes in the header and allow the user to do whatever they want.
  • Using classes from other files is less broken. The lack of including is a good thing although packages and import are basically the same as namespaces and include/using.
  • Being forced to catch exceptions is great, the compiler makes sure that you are doing something with the exceptions later. If you throw or rethrow an exception you then have to mark your function as “throws ” so that the exception and catching the exception propogates up the call stack. The best part about this is that the compiler then knows exactly where an exception should be handled and produces an error if you haven’t handled it or rethrown it.
  • I miss const. There is final but it isn’t quite the same.
  • I miss for example operator overriding. Some built in classes such as String, Array, Vector, etc. could definitely benefit from it. buffer[0] is easier for me to write and understand at first glance than buffer.get(0).  Geometric vector and matrix classes could definitely benefit from operator overloading too for example a = b + c can be understood instantly, a.Add(b, c) is a bit awkward and I have to think about it, “a is being modified, right, b and c are left unmodified, right?”.
  • I miss complex macros and ifdef/ifndef. These can be very helpful, for example using one class on one platform and another class on the other or sharing all the code in a class except for a few lines that are different. Apparently the JVM should be good enough that you can branch on the platform and use oop to change functionality and not lose too much performance. I’m not sure what the replacement is though for a part of your application that just doesn’t compile on other platforms because it uses a platform specific API.

malloc double free/non- aligned pointer being freed set a breakpoint in malloc_error_break to debug

malloc: *** error for object 0x3874a0: double free
***set a breakpoint in malloc_error_break to debug

malloc: *** error for object 0x18a138: Non- aligned pointer being freed
*** set a breakpoint in malloc_error_break to debug

So basically something in your code is screwing around with memory.

Either releasing something that has already been released:

int* x = new x[10];
delete [] x;
delete [] x;

Or releasing something that is not pointing to the start of an allocated block of memory:

int* x = new int[10];
x++;
delete [] x;

The error message isn’t very clear if you have no experience with GDB. GDB is a debugger for your binaries. It allows you to set break points at the start of a function and any time that function is called your application will pause and allow you to debug in GDB. We can then get valuable information back by executing commands to get the backtrace, registers state and disassembly. The advantage of using GDB over Xcode/KDevelop is being able to break into any function, not just functions in your source code. Anyway, this is how I got the backtrace to find out where in my sourcecode I was making a mistake:

gdb
file myapplication
break malloc_error_break
run
backtrace

Now whenever a double free or non- aligned pointer is freed it will break into gdb and we can type in “backtrace” and work out what our code did to trigger this.

libxdgmm

I think the Portland Project from freedesktop.org, is a great idea and
everyone should be supporting it in their applications.

I’ve just created a very small C++ wrapper (libxdgmm) for accessing XDG more easily. To use it, you need libxdgmm.h and libxdgmm.cpp. Just add these to your project and then use them like so:

#include <libxdgmm/libxdg.h>
 
int main(int argc, char** argv)
{
  if (!xdg::IsInstalled()) std::cout<<"XDG is not installed"<<std::endl;
  else {
    std::string data;
    xdg::GetDataHome(data);
    std::cout<<"data=\""<<data<<"\""<<std::endl;
 
    std::string config;
    xdg::GetConfigHome(config);
    std::cout<<"config=\""<<config<<"\""<<std::endl;
 
    // Obviously these have to exist to work.  You can translate the error code returned by calling xdg::GetOpenErrorString(int result);
    xdg::OpenFile("/home/chris/dev/cMd3Loader.cpp");
    xdg::OpenFolder("/home/chris/");
    xdg::OpenURL("http://chris.iluo.net");
  }
 
  return EXIT_SUCCESS;
}

I still have to wrap some of the other functionality, such as XDG_DESKTOP_DIR, XDG_DOCUMENTS_DIR, XDG_MUSIC_DIR, desktop-file-utils, xdg-desktop-menu and xdg-desktop-icon etc. I will wrap these as I need them (Or at special request). I don’t think I will be supporting xdg-screensaver or xdg-mime as I don’t have a use for them right now.

C++0x compiling with gcc

Gcc has some early support for C++0x. You can enable it with -std=c++0x (Note: You can already use Boost without enabling this flag). Enabling this flag broke boost::filesystem for me, but this has already been reported and fixed:

boost/filesystem/operations.hpp

661	661	    inline bool is_empty( const path & ph ) 
662	 	-      { return is_empty<path>( ph ); } 
 	662	+      { return boost::filesystem::is_empty<path>( ph ); } 
663	663	    inline bool is_empty( const wpath & ph ) 
664	 	-      { return is_empty<wpath>( ph ); } 
 	664	+      { return boost::filesystem::is_empty<wpath>( ph ); }

The full patch is much longer, but this seemed to be all I needed to get it to work (Note: You will need to su and then gedit /usr/include/boost/filesystem/operations.hpp).

Anyway, you will want to test it out:

enum A
{
  A_1,
  A_2
};
 
enum B
{
  B_1,
  B_2
};
 
void Test()
{
  B b = 0;
 
  b = true;
  b = 1;
  b = A_1;
  b = A::A_1;
  b = B_1;
  b = B::B_1;
}

The only lines of Test that compile are “b = B_1;” and “b = B::B_1;”. Under C++98/C++03 this would 100% compile, which could easily create bugs where the code compiles but may not be what is intended. We can also get slightly tighter restrictions again, by defining “enum B” as “enum class B”. This restricts the correct lines of Test to “b = B::B_1”, meaning the enum must be fully qualified which should lead to less ambiguous code. In a real situation you will also want to actually initialise b to a decent value initially as well: “B b = B::B_1” for example.

Anyway, this is a pretty trivial example, just a tidy up of the language really, you will want to delve deeper. Variadic templates, Initializer lists, Lambda expressions and closures, New character types, Unicode string literals, Raw string literals and Universal character name literals look good. Extern templates, Inheriting constructors, nullptr, __func__, C99 preprocessor, long long, Extended integral types can’t get here soon enough.

Yearly Update :)

Sudoku Work in Progress
Skysytem background, testing wireframe grid, TombRaider MD3 model, testing material boxes, particle systems, frames per second messages, pegs, shocks, all the necessary elements of a Sudoku game.

It’s been a while, I have like 20 draft entries in WordPress ranging from 1 paragraph comments up to 10 paragraph full on entries that still need that final once over and edit before going live. Actually it might be cool if there was (There probably is) a plugin so that people could optionally go to a page on my blog where they can see everything that hasn’t been published yet, like tagged with “draft” or something and comment on which ones I should flesh out and which ones I should ditch before they are even finished.

Anyway, so I have been working (Getting side tracked while working on) my Sudoku game.

Basically in Sudoku mode you get to select a number from the “palette” at the top and then click on all the places you want it on the board. The solver I have coded up can solve about 80% of Sudoku boards with “human solvable” methods and the remaining 20% can be solved with a combination of human solvable and then resorting to brute force for anything it can’t find. A valid board should not need brute forcing which means that I need to implement more rules for my human solving methods first. I should be doing something like this:

if (solve_human_methods()) ... solved
else ... this board is invalid as it could not possibly be solved by a human without resorting to brute force

However I haven’t implemented all human methods of solving yet, only about 4 or 5 simple ones, actually probably less, there are about 2 or 3 real rules and then 4 or 5 extrapolated rules that are just combinations of the first ones.

Anyway, in First Person mode there is flying around (No clip mode) as well as moving Lara Croft around (Optionally other MD3 models) with sort of appropriate animations based on velocity (But not facing direction yet). One thing I have noticed is that half of the MD3 models I download have different file naming conventions, so at some stage I want to break out some Quake 3 action and see what file names it uses and use that as my standard.

Why all this other stuff in a Sudoku game? Whichever game I am working at the time becomes my test bed application for whatever I feel like implementing when bored. I really need to make a dedicated test bed that does nothing else but demonstrate stuff. I’ve also split my game engine into Spitfire and Breathe portions, which splits the library into two halves, the generic tools for any application (string, math, xml, md5 hashes etc.) and game specific features (OpenGL rendering, audio, physics, MD3 animation, etc.) respectively.

x86_64 Linux C/C++ Test

I use:
gcc
cmake
KDevelop
RapidSVN
Meld

However, don’t go the websites, all of these are available in the (Default?) repositories, so you can either install them via yum, PackageKit or apt-get. Also note: RapidSVN and Meld are only needed if you want to use SVN. Even KDevelop is not required if you have another text editor that you prefer such as gedit/vi/emacs. If you want to create your provide your own make file then you don’t need cmake either.

Anyway, so a simple application that just tests that you can do a 64 bit compile is pretty straight forward.
1) Create your main.cpp file with a int main(int argc, char* argv[]); in it.

# Set the minimum cmake version
cmake_minimum_required (VERSION 2.6)
 
# Set the project name
project (size_test)
 
# Add executable called "size_test" that is built from the source file
# "main.cpp". The extensions are automatically found.
add_executable (size_test main.cpp)

2) Create a CMakeLists.txt that includes your main.cpp.

#include <iostream>
 
int main(int argc, char* argv[])
{
  int *int_ptr;
  void *void_ptr;
  int (*funct_ptr)(void);
 
  std::cout<<"sizeof(char):        "<<sizeof(char)<<" bytes"<<std::endl;
  std::cout<<"sizeof(short):       "<<sizeof(short)<<" bytes"<<std::endl;
  std::cout<<"sizeof(int):         "<<sizeof(int)<<" bytes"<<std::endl;
  std::cout<<"sizeof(long):        "<<sizeof(long)<<" bytes"<<std::endl;
  std::cout<<"sizeof(long long):   "<<sizeof(long long)<<" bytes"<<std::endl;
  std::cout<<"------------------------------"<<std::endl;
  std::cout<<"sizeof(float):       "<<sizeof(float)<<" bytes"<<std::endl;
  std::cout<<"sizeof(double):      "<<sizeof(double)<<" bytes"<<std::endl;
  std::cout<<"sizeof(long double): "<<sizeof(long double)<<" bytes"<<std::endl;
  std::cout<<"------------------------------"<<std::endl;
  std::cout<<"sizeof(*int):        "<<sizeof(int_ptr)<<" bytes"<<std::endl;
  std::cout<<"sizeof(*void):       "<<sizeof(void_ptr)<<" bytes"<<std::endl;
  std::cout<<"sizeof(*function):   "<<sizeof(funct_ptr)<<" bytes"<<std::endl;
  std::cout<<"------------------------------"<<std::endl;
  std::cout<<"Architecture:        "<<sizeof(void_ptr)<<" bit"<<std::endl;
 
  return 0;
}

3) cd to the directory of your CMakeLists.txt and run “cmake .” and then “make”
4) ./size_test output:

sizeof(char):        1 bytes
sizeof(short):       2 bytes
sizeof(int):         4 bytes
sizeof(long):        8 bytes
sizeof(long long):   8 bytes
------------------------------
sizeof(float):       4 bytes
sizeof(double):      8 bytes
sizeof(long double): 16 bytes
------------------------------
sizeof(*int):        8 bytes
sizeof(*void):       8 bytes
sizeof(*function):   8 bytes
------------------------------
Architecture:        64 bit

As you can see this is specific to x86_64. The beauty of gcc is that by default it compiles to the architecture it is being run on. I had previously thought that it would be a world of pain, making sure that my compiler built the right executable code and linked in the correct libaries. I know this project doesn’t use any special libraries, but (because of cmake?) the process is exactly the same as using cmake under 32 bit to make 32 bit executables. You just make sure that they are there using Find*.cmake and then add them to the link step:

SET(LIBRARIES
  ALUT
  OpenAL
  GLU
  SDL
  SDL_image
  SDL_net
  SDL_ttf
)
# Some of the libraries have different names than their Find*.cmake name
SET(LIBRARIES_LINKED
  alut
  openal
  GLU
  SDL
  SDL_image
  SDL_net
  SDL_ttf
)
FOREACH(LIBRARY_FILE ${LIBRARIES})
  Find_Package(${LIBRARY_FILE} REQUIRED)
ENDFOREACH(LIBRARY_FILE)
 
# Link our libraries into our executable
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIBRARIES_LINKED})

Note that we don’t actually have to specify the architecture for each package or even the whole executable. This is taken care of by cmake. Anyway, it is not some mysterious black magic, it is exactly the same as you’ve always been doing. Cross compiling is slightly different, but basically you would just specify -m32 and make sure that you link against the 32 bit libraries instead. If I actually bother creating another 32 bit executable in my life I’ll make sure that I document right here exactly how to do a cross compile from 64 bit.

The advantages of 64 bit are mmm, not so great unless you deal with really big files/memory ie. more than 4 GB. Perhaps more practical are the extra and upgraded to 64 bit registers so you may see an increase in speed or parallelisation of 64 bit operations, for example a game may want to use 64 bit colours (ie. 4x 16 bit floats instead of 4x 8 bit ints to represent an rgba pixel.

Things to watch out for:
int is still 32 bit! If I were implementing the x86_64 version of C++ standard/gcc/in a perfect world this would have been changed to 64 bit, ie. “int” would be your native int size, it’s logical, it makes sense. However, I do understand that this would have broken a lot of code. The problem is, if int != architecture bits, then why have it at all, why not drop it from the standard and just have int32_t and int64_t and be done with it. Then if a program chooses it can have:

typedef int32_t int;

or

typedef int64_t int;

as it sees fit. Anyway.
Pointers are now 64 bit! So you can use them with size_t but cannot use them with int
Under linux x86_64 gcc sizeof(int*) == sizeof(function*), however, this is not guaranteed anywhere. It may change on a certain platform/compiler. Don’t do stuff like this:

int address = &originalvariable;

gcc should warn you (you may need to turn on these warnings -Wformat -Wconversion).

All in all, if you have been writing standard code and using make/cmake it should be relatively pain free to upgrade to 64 bit.

const int vs. enum vs. #define

Example A:

int GetValue0()
{
  return 10;
}
 
int GetValue1()
{
  return 10 + 10;
}
 
int GetValue2()
{
  return 10 * 10;
}

So if all of the values 10 represent a common magic number then you are going to want to extract that value to one location instead of the 5 that it is in at the moment. How do we do this?

Say we call the value MAGIC_NUMBER (Of course, in a real life situation you would use a better name than this, wouldn’t you? Something like PI, GST_PERCENTAGE, NUMBER_OF_CLIENTS, etc.) we would then have this code.

Example B:

int GetValue0()
{
  return MAGIC_NUMBER;
}
 
int GetValue1()
{
  return MAGIC_NUMBER + MAGIC_NUMBER;
}
 
int GetValue2()
{
  return MAGIC_NUMBER * MAGIC_NUMBER;
}

Great. The problem now is, how do we tell our program about MAGIC_NUMBER?

If you originally started programming C then your first instinct may be to use:

#define MAGIC_NUMBER 10

The main problem here is that the compiler may not realise that all of the places you use MAGIC_NUMBER are linked so it may not realise that it can factor it out. The other problem with this method is the lack of type safety. You can use MAGIC_NUMBER with sign/unsigned ints, char, bool etc. The compiler may not warn you about converting between these types. For an int this isn’t really a problem, but const float PI = 3.14…f should give you a warning when you try to initialise an int to it. This is good news as it requires you to cast if you really want to do it, which then shows other programmers than you have actually thought about what you are doing and what is happening to the value as it passes through each variable.

You might be tempted to use:

int MAGIC_NUMBER = 10;

This is much better as it adds type safety, however you can do even better than that,

const int MAGIC_NUMBER = 10;

This way it isn’t “just” a global variable, when you declare it as const you are telling the compiler that it will never change in value which means that it can make all sorts of assumptions about how it will be used. Your compiler may or may not factor out/in this value, it may or may not insert 10 + 10 and 10 * 10 into those functions for you at compile time. Using a const int means that the compiler gets the choice of using either the value directly or using a variable containing that value, and I trust the compiler more than myself to make that decision. Because it knows the value of MAGIC_NUMBER at compile time and knows that it will never change at runtime it can actually do the calculation and insert that value instead.

int GetValue0()
{
  return 10;
}
 
int GetValue1()
{
  return 20;
}
 
int GetValue2()
{
  return 100;
}

The other magic number container is enum. It varies slightly to const int as it is more for collections of values where you want to identify something by what type it is.

enum RESULT
{
  RESULT_FILE_DOWNLOADED,
  RESULT_CONNECTION_FAILED, 
  RESULT_FILE_NOT_FOUND,
  RESULT_DISCONNECTED
};
 
RESULT DownloadFile(const std::string& url)
{
  // Pseudocode
  if (could not connect) return RESULT_CONNECTION_FAILED;
  if (file not found) return RESULT_FILE_NOT_FOUND; 
 
  if (disconnected) return RESULT_DICONNECTED;
 
  return RESULT_FILE_DOWNLOADED;
}

In this way we can get rid of magic numbers and (In C++0x at least with enum class) get some type safety, your compiler will hopefully complain if you try and return an integer instead of a RESULT.