söndag 1 november 2009

Building STLPort for Windows CE with Visual Studio 2005

As we want to use Boost in our WinCE project, we needed a full implementation of STL (including streams support). I never got Microsofts STL implementation to build for our device, probably because of some difference in the C library on our SDK. Therefore I decided to use STLPort which is designed to be more portable.

The documentation on STLPort is far from comprehensive, and it took me a great deal of time until I found the right information in the docs and on the forum to build the thing. Below is the script that sets up all needed enviornment variables and configures STLPort.

It should work for other versions of MSVC as well. Just change all the set to point to the right directories. I am not sure the use-boost is really needed

@echo off
set STLROOT=C:\STLport-5.2.1
cd %STL_ROOT%


set OSVERSION=WCE500
set PLATFORM=BACX
set ARCH=ARMV4I
set SDKROOT=C:\workspace\Alpha\main\SDK\wce500
set VSROOT=C:\Program Files\Microsoft Visual Studio 8
set BOOSTROOT=C:\Program Files\Boost\boost_1_40_0


call "%VSROOT%\VC\vcvarsall.bat"

set PATH=%VSROOT%\VC\ce\bin;%VSROOT%\VC\ce\bin\x86_arm;%VSROOT%\VC\bin;%VSROOT%\Common7\IDE;;%PATH%


set INCLUDE=%SDKROOT%\%PLATFORM%\include\%ARCH%;%SDKROOT%\%PLATFORM%\ATL\include;;%INCLUDE%


set LIB=%SDKROOT%\%PLATFORM%\lib\%ARCH%;%SDKROOT%\%PLATFORM%\ATL\lib\%ARCH%;%VSROOT%\VC\ce\lib\%ARCH%;;%LIB%


set CC=cl.exe
set TARGETCPU=ARMV4I
set CFG=none

call configure evc8 -x --with-static-rtl --use-boost %BOOSTROOT%

cd %STL_ROOT%/build/lib
nmake install

tisdag 22 september 2009

Invoking Properties in .NET

I just stumbled across a problem recently in a Windows Form application I was writing in C#. I wanted to make an update to the GUI from another thread, using Invoke(). The problem was that the update included setting a Property, and not a normal method call. And .NET (at least 2.0, I don't know about fancy 3.5 or upcoming 4.0) don't support Setting and Getting Properties.

This might seem strange, as setting a property is really only making a method call. However, there are two common solutions for this.

The first is to simply write a method that sets the property, and then Invoke() this method. However, I had plenty of classes and places where I had to set Properties, so this was not an ideal solution.

The other solution, which I ended up using, is to use Reflection to get an MethodInfo object of the Property's set. You can then use that object to create a delegate dynamically. In the example, I set the class own SetID property to "4".:


public delegate void test(int i);

public partial class Form1 : Form
{
private int setId = 0;

public int SetID
{
set
{
setId = value;
}
}

void anotherThread()
{
MethodInfo mi = this.GetType().GetProperty("SetID").GetSetMethod();
Delegate del = Delegate.CreateDelegate(typeof(test), this, mi);
this.Invoke(del, 4);
}
}

lördag 15 augusti 2009

All programmering är inte webprogrammering

I dessa dagar hör man oftare och oftare folk (mest webprogrammerare och självutnämnda evangelister) som påstår att applikationer i form av exekverbara filer snart kommer att vara helt borta, ersatta av webbapplikationer.

Visst, det finns en stark trend att användarapplikationer mer eller mindre helt håller på att flytta till webben. Men vad alla dessa männiksor glömmer är att bara en del av världens kodbas ligger i sådana program.

Jeff Atwood, som annars ofta säger vettiga saker, gick så långt som att säga att:

"Pretty soon, all programming will be web programming".

Har Jeff måhända aldrig hört talas om:
  • Automation och maskinkontroll? Jag har inga direkta siffror, men den sammanlagda kodbasen i alla världens fabriker passerar nog långt dagens webbapplikationer. Detta är ofta kritiska realtids-system som absolut aldrig skulle passa på webben.
  • Simulering och beräkning? Också något som nästan alla fabriker använder sig av, samt forskare och labbpersonal världen över. Beräkningstungt och minimal nytta att flytta till webben förutom möjligtvis viss presentation.
  • Spel? Tunga 3D-spel kommer alltid att kräva extremt optimerade exekverbara filer i grunden (även om de kanske inte exekveras lokalt).
  • Embedded-mjukvara? Allt från klockor, bankomater, kortläsare, tunnelbanespärrar, sjukhusutrustning, till avancerade telefoner och handdatorer använder inbyggd mjukvara som självklart inte alls lämpar sig att flytta till webben.
  • Drivrutiner? Inget behöver tilläggas här.
  • Annat? Unika system som t ex hela världens mobilnät (allt från radiointerface till samtalsrouting), världens fasta telefonnät, satteliter, trafikövervakning, etc, etc?
Det är bara att inse, folk som tror att all programmering kommer att vara webbprogrammering är antingen inte insatta i dagens digitala samhälle, eller så är de önsketänkare. Och tur är väl det, för webbprogrammering är ju så extremt trist.

tisdag 9 juni 2009

Från hanterad kod till C++, del 4

Detta är del 3 i inläggsserien om att gå från .NET/Java till C++. Förra delen handlade om Boost, det bästa tillägget till standard C++ där ute. Denna del ska handla om kodkonventioner. C++ lider av problemet att det är extremt fritt, och det är lätt att göra subtila felsteg som skapar stora problem senare.

Detta inlägg presenterar därför 9 stycken konventioner man bör följa då man programmerar C++. Alla dessa är tagna från den fantastiska boken "C++ Coding Standards" av Sutter & Alexandrescu, som innehåller 101 "best practices", med lite modifierade exempel och mycket mindre text.

Jag har valt ut de 9 jag finner mest intressanta och användbara, men utelämnat de mest basala (som t ex, att man alltid ska skriva include guards, något som de flesta IDE:er sköter åt automatiskt en nuförtiden, eller att man ska minimera global data).

Använd const proaktivt (punkt 15)
Jag har tidigare pratat om på hur många sätt const kan användas. Även om det är jobbigt att tänka efter precis när man bör ha en const-deklaration skapar det mycket robust kod, speciellt då man skriver SDKer och APIer för andra programmerare.

const är framförallt viktigt att använda för parametrar och returvärden då man hanterar pekare och referenser, och som regel ska man alltid returnera ett const pekare om man vill att anroparen inte ska kunna ändra den.

const har förmågan att propagera genom koden; om man deklarerar const för en medlem eller funktion slutar det ofta att man måste deklarera anropade parametrar och funktioner const. Detta är dock en feature.

Exempel. Det rätta sättet att skicka in en sträng (som inte ska ändras) till en funktion är:

void func(const std::string &str);

Vi deklarerar den som en referens för att slippa onödig kopiering, men som const för att försäkra oss att ingen modifikation av strängen sker.

Minimera cykliska beroenden (punk 22)
Det är väldigt lätt att råka skriva kod där två header-filer inkluderar varanndra, antingen direkt eller genom en cirkel. Detta tyder ofta på att designen i koden är dålig, och även om kompilatorn kan klara av detta (vilket vissa kanske tycker är direkt fel) så avråds man från detta.

Ändock värre är om man hamnar i ett cykliskt beroende med libs eller dller. Detta är extremt dålig design, då ett bibliotek ska symbolisera en oberoende modul, och två bibliotek som beror på varanndra betyder att de egentligen är en enda modul.

Ta parametrar som värden, referenser eller pekare på rätt sätt (punkt 25)
Om man är ny till C++ kan det vara komplicerat att på direkten se hur man bör skicka parametrar till funktioner. Ovan visades ett exempel med const och referens. Sutter, Alexandrescus har några tips:
  • const:a alltid pekare och referenser till input-parametrar
  • Ta värden främst som primitiva typer och sådana typer som är billiga att kopiera
  • Skicka som referens om funktionen inte tänker spara en pekare till argumentet.
Föredra en medlem istället för arv (punkt 34)
Jag tycker att denna punkt är väldigt intressant då jag ser många som använder arv alldelles för flitigt. I många fall är det bättre att bädda in en medlem av en klass i en annan klass (som privat medlem) istället för att skapa en klasshirearki via arv. Du har mycket bättre kontroll över hur klassen kallas, du får kortare kompileringstider, och du får inte lika nära koppling.

Man ska t ex komma ihåg att många klasser inte alls är tänkta att ärva från, speciellt gäller detta nästan alla klasser i std.

Deklarera basklassers destruktorer public och virtual, eller protected och icke-virtuella (punkt 50)
Detta är en ganska subtil punkt som kan orsaka väldigt konstiga runtimefel om man glömmer den. Säg att man deklarerar klasses Base:s destruktor public. I klassen Derived som ärver från Base deklarerar man ingen destruktor. I följande kod:


Derived *d = new Derived();
Base *b = (Base*)d;
delete b;


kommer vi att få ett odefinierat beteende, då Base desturktor anropas, men då b egenligen pekar till en objekt av Derived.

Om Base:s destruktor hade varit virtuell, hade istället Derived:s destruktor kallats, vilket är beteendet vi är ute efter.

Tillåt eller förbjud kopiering explicit (punkt 53)
C++ kompilatorer lägger automatiskt till en copy constructor (och en copy assignment constructor) om man själv inte definierar någon. Detta är ofta bra, men det finns många klasser som aldrig någonsin är tänkta att kopieras. Exempelvis finns det ingen vettig mening med att kopiera en klass som representerar en nätverksförbindelse (som ju binder upp en systemresurs).

För att inte andra ska göra misstaget att råka kopiera din klass är det bäst att explicit förbjuda detta. Det finns olika sätt, men jag föredrar att låta klassen som inte ska kunna kopieras ärva (privat) från boost::noncopyable. Ett annat sätt är att deklarera copy konstruktorerna privat.

Kasta som värde, fånga som referens (punkt 73)
Detta är standardsättet att kasta och fånga undantag på i C++, något som inte är lätt att veta som nybörjare. För det mesta ska man också fånga som const:

try
{
if (fails)
throw MyException();
}
catch (const MyException &e)
{
cout << "Problem"; }


Använd std::vector och std::string::c_str() för att prata med icke-C++ APIer (punkt 78)
För att kommunicera med externa APIer, skrivna i t ex C, behöver man inte transformera alla sina std::vector till arrayer, som många tror. En std::vector fungerar från C sett precis som en array, där första elementet pekar till början på std::vector. Och en std::string som man kallar c_str() på returnerar en C-lik null-terminerad char*.

Föredra algoritmanrop framför handskrivna loopar (punk 84)
Det är lätt att av gammal vana skriva en egen loop för att göra en operation på en kontainer. Dock så finns det massor med fina funktioner i STL och i samarbete med boost::bind kan man skriva många operationer som one-liners, med mycket lägre risk för fel.

Ett exempel: Jag ville nyligen hitta ett object av typen Exercise i en vector där dess medlem std::string name matchade ett namn jag ville söka på, name. Detta går ju att skriva för hand, men denna lösning blir mycket snyggare och säkrare:


std::vector::iterator it = std::find_if(exercises.begin(), exercises.end(), boost::bind(&ExerciseManager::compare, _1, name));


Och i samma klass definieras compare-funktionen:


bool ExerciseManager::compare(Exercise ex, const std::string &name)
{
if (name.compare(ex.name))
return false;
else
return true;
}

Efter anropet kommer iteratorn it (magiskt?) att peka på första elementet med matchande namn. Läs på om STL:s sök - och sorteringsalgoritmer och om boost::bind, om du inte redan gjort det!

lördag 23 maj 2009

Sydkoreaner är coola!

Jag har alltid beundrat sydkoreaner. I dagens DN står det om ex-presidenten som hoppat ut för en klippa då han blivit anklagad för att ha tagit emot mutor.

Detta är precis den bergssäkra vilja som byggt upp denna fantastiska nation. Män som Boxer visade ingen nervositet inför en Starcraft-match, och hans ansiktsuttryck skönjde inte en känsla, oavsett om han vann eller förlorarde. Man kan säga att Boxer och ex-presidenten är två sidor av samma mynt. Snacka om riktiga män!

onsdag 13 maj 2009

Medierna och datorerna

Idag läste jag DN:s artikel "Illegal fildelning minskar stort", den senaste i en lång rad artiklar relaterade till Piratebayrättegången, fildelning och nätneutralitet. Det slog mig då, visserligen inte för första gången, hur extremt stor makt media har över vilken information gemene man har tillgång till.

Jag kommer ihåg hur det var i början av 90-talet. På denna tid hade nog inte en ppm av den vuxna befolkningen koll på vad piratkopiering, Internet eller neddladdning var. Och det fascinerande är att det på den tiden redan existerade en hel datakultur bland yngre folk.

Till exempel, då Doom släpptes 1993 laddades första sharewareversionen hem av 10 miljoner människor (ungefär lika många som spelar WoW idag). Dataspelsindustrin i USA var redan en mångmiljardindustri. Det fanns redan stora grupper som släppte spel på BBS:er och Internet, som t ex Razor 1911, och det hölls ett antal stora rättsliga processer mot fildelarsiter.

I vanlig media såg man dock inte ett knyst om något av detta. Att försöka förklara för någon att man sysslade gaming, nerladdning eller att chatta på IRC var näst intill omöjligt. Och om folk förstod tyckte dom att det var lite udda. Det var en gigantisk ungdomskultur som aldrig uppmärksammades av folk över 25 år.

Varför tog det då sådan tid för medierna att uppmärksamma datorkulturen? Antagligen beror det till största delen på föryngringen av journalisterna. Många journalister är ju i 30-års åldern och har växt upp med detta. En annan orsak är självklart att datorkulturen är ännu större idag.

Det som är tråkigt (och lite skrämmande) är att det alltså krävs att ungdomarna växer upp och blir journalister innan resten av befolkningen kan upplysas om ungdomskulturen i fråga. Man undrar om distribution av film och musik, samt Internetlagar, hade kunnat sett annorlunda ut om ämnet hade debatterats redan för 15 år sedan.

måndag 20 april 2009

Template specialization sucks

A wise man (Herb Sutter) once said that you should avoid function template specialization. After what I experienced today, I can only agree.

As we know, the compiler has to do a lot of background work when you declare templates. Unfortunately, all compilers handles templates a little bit differently. Watch this code taken from stackoverflow which was supplies as an answer to me regarding a template problem:

template <typename X> struct Test {}; 
struct X
{
template <typename T>
static void f( Test<T> );
};

// template definition:
template <typename T>
void X::f( Test<T> ) {
std
::cout << "generic" << std::endl;
}
template <>
void X::f<void>( Test<void> ) {
std
::cout << "specific" << std::endl;
}

int main()
{
Test<int> ti;
Test<void> tv;
X
::f( ti ); // prints 'generic'
X
::f( tv ); // prints 'specific'
}
We have here a simple template specialization for the void type. This will compile and run fine under any compiler.

However, often we use multiple static libs. If we instead put the template specification in another lib and linked it to our main application where main() resides, it would still work fine. On some compilers.

It turns out that MSVC can handle this without any problems, while gcc will generate a "multiple definitions" error for f(). Obviously, this has something to do with how the function tables are constructed during linking, but I have not explored it more deeply than that.

As it happens, there's a fix for this problem. Declaring the speccialization as inline will remove the compiler error. With inline , a copy of the function body is inserted everywhere the function is called. No normal calls (including a jump, stack things etc) are done.

However, the point here is that templates in general and template specialization in particular, are advanced concepts that should only be used with uttermost care in your code. There is no way to underestimate the benefits of having code that compiles on all standard compilers. Therefore, follow Sutter's advice and use template specialization only when you really have to.

söndag 19 april 2009

Från hanterad kod till C++, del 3

Detta är del 3 i inläggsserien om att gå från .NET/Java till C++. Förra delen handlade om olika typer av keywords och mekanismer i C++ som är krångliga. Denna del ska handla om Boost, det bästa tillägget till Standard C++.

Boost
Många lär sig tidigt att använda Standard Template Library, STL, till C++. STL inkluderar många klasser man använder dagligen t ex std::vector, std::map och std::string, för att nämna de vanligaste. STL är helt okej, men det finns en ramverk som delvis ersätter och delvis kompletterar STL, nämligen Boost.

Boost underhålls av några mycket tunga namn från C++ världen, många som även sitter med i C++ standardkommite. Detta har resulterat i att flera Boostklasser nu är en del av Standard C++.

Jag tycker att Boost är det absolut bästa komplementet till C++, och många av Boost klasser som ersätter STL är betydligt bättre än originalet. Boost är också mycket trevligt att använda; den mesta koden ligger direkt i header-filerna så man behöver ofta inte ens lib-filerna. Självklart är också hela Boost plattformsoberoende.

För att visa hur trevliga Boostbiliboteken är presenterar jag några klasser som vi ofta använder på jobbet.


FOREACH
Många språk (t ex C# och Perl) har en inbyggd foreach funktionalitet för att iterera igenom listor. I C++ finns det flera olika försök till att implementera detta, men Boost har lyckats bäst. Syntaxen är väldigt smidig och mycket lik den i C#:

#include <boost/foreach.hpp>

// skriver ut "2" på skärmen

void main()
{
std::vector<int> vec;
vec.push_back(2);

BOOST_FOREACH(int i, vec)
{
std::cout << i << std::endl;
}
}

Tuple
Väldigt ofta vill man på ett enkelt sätt associera två eller fler objekt med varann. T ex kanske man bara snabbt vill få ut en x,y punkt ur en funktion, och man orkar inte skapa en klass eller struct bara för att uppnå detta. Då är tuples perfekta. Följande exempel visar hur man skapar tuples och hämtar värdena i en tuple.

#include <boost/tuple/tuple.hpp>


boost::tuples::tuple<std::string, int> getPerson()
{
boost::tuples::tuple<std::string, int> point_tuple("Per", 20);
return point_tuple;
}

void main()
{
boost::tuples::tuple<std::string, int> pers = getPerson();

std::string name = boost::tuples::get<0>(pers);
int age = boost::tuples::get<1>(pers);
}

Om man inte vill ange typerna då man skapar en tuple kan man låta Boost gissa dem genom att använda make_tuple (exemplet taget från boost.org):


tuple<int, int, double> add_multiply_divide(int a, int b)
{
return make_tuple(a+b, a*b, double(a)/double(b));
}

Det finns massor av mer funktionalitet kring tuple, som t ex jämförelser och input/output. tuples lämpar sig bra tillsammans med en typedef eller två, då uttrycken tenderar att bli långa.


Any
Man vill ofta ha ett sätt att lagra helt olika, orelaterade typer i en lista eller annan behållare. Det kan röra sig om inställningar, kolumner från en databas, funktionspekare eller vad som helst. Genom åren har man använt sig av flera olika alternativ för att göra detta. Ett sätt är att kasta allt till void*, vilket är ett väldigt osäkert och fult sätt. Man kan även använda sig av union eller någon form av arvstruktur med en generell basklass.

Det överlägset bästa sättet är att använda sig av boost::any. boost::any lagrar på ett typsäkert sätt vilken typ som helst. Se följande exempel för deklarationen:

#include <boost/any.hpp>

void main()
{
std::vector<boost::any> anyValues;

int i = 40;
std::string s = "hej";

boost::any anyInt = i;
boost::any anyString = s;

anyValues.push_back(anyInt);
anyValues.push_back(anyString);
}
För att avgöra vilken typ en boost::any har använder man metoden type():

BOOST_FOREACH (boost::any a, anyValues)
{
if (a.type() == typeid(int))
int i = boost::any_cast<int>(a);
else if (a.type() == typeid(std::string))
std::string s = boost::any_cast<std::string>(a);
}

Smart pointers

Genom mekanismen new/delete tvingas man som programmerare att komma ihåg att avallokera minne vid rätt tidpunkt i C++. Detta är något helt främmande för oss som använder hanterade språk där Garbage Collector automatisk avallokerar minne som inte längre används.

Sån tur är behöver man inte tänka på sådant i C++ längre; det finns flera implementationer av s.k smarta pekare som ser till att minnet frigörs automatiskt. Den vanligaste är boost::shared_ptr. Den använder referensräkning för att hålla reda på när ett objekt kan deallokeras.

Genom att alltid göra som i exemplet nedan då du tänkte skriva "new" slipper du helt minnesläckor associerade med dynamisk minnerallokering:

#include <boost/shared_ptr.hpp>

class MyClass
{
public:
void memberFunction() {;};
};

typedef boost::shared_ptr<MyClass> MyClassPtr; // bra med typedef då det tenderar bli långa rader


void main()
{
MyClassPtr myclass(new MyClass()); // istället för bara "new"

myclass.get()->memberFunction(); // get() returnerar en vanlig pekare till klassen så medlemmar kan anropas

} // här kommer myclass automatiskt att raderas

Om man vill skapa en smart pointer till en array bör man använda shared_array. shared_array är egentligen identisk med shared_ptr, men den använder sig av new[] och delete[], som sig bör för pekare till arrayer.

En sak man måste tänkta på är att aldrig stoppa en smart-pointer inuti en annan smart-pointer. Detta kommer att resultera i att boost försöker deallokera objektet två gånger, vilket ger ett runtime-fel. Man ska också komma ihåg att det inte bara är boost som implementerar smart-pointers; därför måste man se till att det man stoppar in i en boost::shared_ptr inte redan är "smart-pointifierad" sedan tidigare om man använder något externt API.


Thread

Boost definierar en plattformsoberoende trådmekanism, boost::thread. Det trevliga är just att den är plattformsoberoende; man slipper använda Windows thread, pthreads eller något GUI-specifikt trådbibliotek (MFC, GTK och QT har alla egna trådklasser).

Självklart implementeras boost::thread med antingen Windows threads eller pthreads beroende på system, men detta är inget vi behöver bry oss om. Enklaste tänkbara exemplet:

#include <boost/thread/thread.hpp>

void func()
{
}


void main()
{
boost::thread thrd(&func);
}

Ovan startar omedelbart en tråd som börjar exekvera func().
Ibland vill vi skicka in ett argument till funktionen som ska köras. Innan boost 1.35 var det lite krångligare, men nu kan man helt enkelt skriva:

#include <boost/thread/thread.hpp>

void func(int inArg)
{
// kallas med inArg = 243
}

void main()
{
boost::thread thrd(func, 243);
}
Det är inga problem att knyta en medlemsfunktion till en tråd:

#include <boost/thread/thread.hpp>

class MyClass
{
public:
void fun(int inarg)
{
// ...

}
void runThread()
{
boost::thread(&MyClass::fun, this, 243);
}
int m_i;
};
Förutom detta finns en uppsjö med olika mutex att använda för att trådsäkra och synkronisera din kod. Se boost dokumentation.


lexical_cast

Ofta vill man kunna röra sig mellan siffror och strängar på ett smidigt sätt. Tex vill man kanske översätta

std::string = "3.5"

till en double eller int vid senare tillfälle. Det finns lite olika sätt att göra detta. Man kan använda atoi, atof, sprintf osv osv. Boost definierar istället en enda cast, lexical_cast, för allt sådant. Koden nedan är självförklarande.

#include <boost/lexical_cast.hpp>

void main()
{
std::string s = "3.5";

double d = boost::lexical_cast<double> (s);
int i = boost::lexical_cast<int> (s);
std::string s2 = boost::lexical_cast<std::string> (i);
}

function och bind

boost::function och boost::bind är två fantastiska verktyg för att (bland annat) skapa och använda funktionspekare och att ändra funktioners aritet. Koncepten är hyfsat avancerade och förtjänar ett helt eget inlägg. Just nu kan jag bara nämna att detta är vad du ska använda då du behöver funktionspekare eller unära funktioner i C++.

söndag 12 april 2009

What are you doing to my PS3, Sony?

Just felt the urge to rant for a minute. After upgrading to the newest PS3 firmware (2.70), I, toghether with many others, found I can no longer stream files from my mediaserver. All files turn up as "unsupported data", and apparently, there is no fix, 'specially since you can't downgrade the damn thing!

I use LinkSys NSLU NAS running Mediatomb as a mediaserver for the PS3, among other things, and it has so far served me flawlessly. Let me put in a good word for the NSLU while I'm at it.

This affordable little piece is a real wonder if you use it to run Linux. I use it for a development MySQL Server, SVN, media streaming (or I did until now), Bittorrent client, and as a general fileserver. The NSLU package repository is huge; you can use for for lots of other stuff as well. For about $100, this is not bad.

Well, enough about that. I hope Sony either fixes this in the next release or provides a downgrade capatibility.

Update:
It seems the 2.70 firmware re-introduced an old bug in the DLNA protocol regarding divx playback. A fix in Mediatomb for this can be found here.

torsdag 2 april 2009

Script to add svn version to your code

In the project I'm currently in, I found it very convenient to include the SVN version number of the release in the application's GUI. If a customer has a problem, we then knows for sure what version they are using, and we don't have to rely on our sometimes shaky release management being correct.

A bash script puts the current SVN version number in a #define in a C++ header file, which is then included in the project and displayed in the 'About box', next to the official version number.

I have included the script below that extracts the version number from the top level .svn/entries database in the project, and puts it in a file VERSION_CPP_FILEPATH that contains the row "#define SVN_VERSION = "

This bash script is then executed as a pre-build action in our IDE.

#/!bin/sh
VERSION_CPP_FILEPATH=../inc/version.hpp
SVN_ENTRIES_PATH=../../.svn/entries

VERS=`cat $SVN_ENTRIES_PATH | grep dir -A 2 | sed -n '2p'`
sed "s/#define SVN_VERSION .*/#define SVN_VERSION $VERS/g" $VERSION_CPP_FILEPATH > tmp.hpp
rm $VERSION_CPP_FILEPATH
mv tmp.hpp $VERSION_CPP_FILEPATH

onsdag 1 april 2009

Från hanterad kod till C++, del 2

Detta är del två i inläggsserien "Från hanterad kod till C++". Del 1 handlade främst om pekare och keywordet new, två ganska jobbiga C/C++ begrepp. Denna del handlar om lite olika mekanismer i C++ som jag tycker kan vara förvirrande i början. En exempel är keyword som får helt olika betydelse beroende på i vilket sammanhang de används. Andra exempel är mekanismer som syntaktiskt är lika andra språk men som i C++ fungerar på ett speciellt sätt.

Casting
C++ har ärvt mycket funktionalitet från C som man inte bör använda. En sådan grej är typecasting. Följande kod kompilerar fint i en C++ kompilator:

void func(DerivedClass *d)
{
BaseClass *b;
b = (BaseClass*) d;
}

Detta ser även identiskt ut med Java/.NETs typecasting. Hursomhelst avråds man från att typecasta på detta sätt i C++, i varje fall för klasser och pekare. För grundtyper tycker jag dock att ovanstående s.k C-style casting är helt okej:


double
d = 3.3;

int i = (int) d;

Men för klasser och pekare, som sagt, bör man använda de i C++ fördefinierade operatorerna:

static_cast (expression)
dynamic_cast (expression)
const_cast (expression)
reinterpret_cast (expression)

De två man använder ofta av dessa är static_cast och dynamic_cast. Dessa finns mycket bra beskrivna på MSDN men jag ska presentera dem i sin korthet.

static_cast

static_cast är den "hårdaste" typen av casting; du tvingar kompilatorn att försöka casta mellan de två typerna, utan att någon runtime-kontroll görs om det går. Detta kan vara bra t ex vid casting nedåt i ett klassträd, då du är säkert på att klassen du vill casta även är av typen du castar till. Till exempel:

class B {};
class D : public B {};

void f(B* pb)
{
D* pd2 = static_cast(pb); // du vet att pb är en tidigare nedåt castad instans av D
}

Om du i exemplet ovan skulle råka ha fel (B är inte en istans av D) kan du få ett allvarligt fel, som t ex access violation.

dynamic_cast
dynamic_cast, vilket kanske är det vanligaste sättet att casta i C++, är mer säkert än static_cast. Vid en dymanic_cast sker en runtime-kontroll av att typerna stämmer, och även kompilatorn skulle klaga om man i exemplet ovan bytte ut static_cast mot dynamic_cast. dynamic_cast fungerar dock bara på pekare och referenser.

const
Ett exempel på ett fult keyword i C++ är const, då det får helt olika betydelser beroende på hur det används. Här är fem exempel:

MyClass
{
static const int myConst = 30; // exempel 1

const char* funcOne(int arg); // exempel 2

int funcTwo(const int arg); // exempel 3

int funcThree(int arg) const; // exempel 4

int funcFour(const BigClass &arg); // exempel 5

};

Första exemplet är enkelt, här deklarerar vi en vanlig konstant precis som i Java/.NET.

I exempel 2 används const för att garantera att returtypen är konstant. Om vi försöker ändra den returnerade char* så kommer vi att generera ett kompileringsfel, vilket är praktiskt just då man returnerar pekare och arrayer som man inte kan ändra på hur man vill.

I exempel 3 säger vi till kompilatorn att arg inte får ändras inne i funktionen (detta används oftast för pekare och referenser, som vi annars skulle kunna påverka inne i funktionen)

I exempel 4 säger vi att funktionen i sig aldrig kommer att ändra på någon medlem i MyClass. Detta kan vara bra för att försäkra sig om att ett funktionsanrop enbart är av ”get”-typ. Om vi försöker ändra på medlemar i klassen kommer kompilatorn att klaga.

Exempel 5 är likt exempel 2, men anledningen att const används här är av ett annat skäl. &-tecknet används här för att slippa att BigClass copy-constructor kallas (vilket ju inte sker då man skickar in en referens i funktionen). Programmeraren vill samtidigt förtydliga till de som ska använda funktionen att &-tecknet inte alls betyder att funktionen kommer att ändra arg, och därav const keywordet.

Templates
Motsvarigheten till generics i Java/.NET heter templates i C++ (eller tvärtom egentligen, då C++ var före). Det handlar alltså om att man kan skicka in en vid kompileringstid okänd typ som argument till en funktion eller som medlemsvariabel i en klass. I Java/.NET finns ju också grundtypen object, med vilken nästan samma sak kan uppnås. Dock så rekommenderas man att använda generics då man kan. I C++ finns inte object, så här måste man använda templates.

I Java/.NET används generics nästan uteslutande för listor av olika slag, men i C++ kan man se templates användas lite friskare, och de kan i vissa specifika tillämpningar verkligen bidra till snygg kod. Jag ska inte brodera ut för mycket i detta ämne, då mekanismen är väldigt lik den i Java/.NET. Det som dock kan nämnas är att C++ igen har förvirrat saker och ting genom att man kan deklarera templates på flera olika sätt, med precis samma betydelse. Till exempel är det ingen skillnad på de två följande deklarationerna:

template <class T> func(T arg);
template <typename T> func(T arg);
Som sagt kan templates användas både för enskilda funktioner (som ovan), eller för en hel klass. Man kan även definiera flera template-typer (här nedan för en hel klass):
template <class T, class U>
class MyClass
{
T member1;
U member2;
};

Det man ska tänka på med templates är att även om de syntaktiskt är mycket enkla, så gör kompilatorn en mängd saker bakom kulisserna för att det ska fungera. Detta kan ibland få oväntade effekter för dig som programmerare. Ett exempel är att function templates måste definieras i include-filen (och inte bara deklareras där, alltså) för att du ska kunna kalla funktionen från en annan fil. Detta har att göra med hur kompilatorn "gissar" vilka typer som funktionen ska förvänta sig.

copy constructor
Som jag nämnde i del 1 så används en implicit copy-constructor för att kopiera typer då argument ska slussas in i funktioner och ut som returvärden, samt vid tilldelningar. Undantaget är om man skickar pekare eller referenser. Detta är som sagt förvirrande för oss från Java/.NET då vi är vana vid att man alltid automatiskt skickar referensen till en klass, vad man än gör. Hursomhelst är det så det fungerar i C++, och det är bara att vänja sig.

Det finns möjlighet för en själv att definiera en copy-constructor till ens klass, vilken liknar den vanliga konstruktorn i utseende. Varför vill man göra detta? Svaret är att på vissa klasser duger inte den implicita copy-constructorn. Detta är fallet om en klass innehåller pekare till dynamiskt allokerat minne, alltså då keywordet new har använts i klassen. Vi måste då skriva en egen copy-constructor. Se följande exempel snott från www.codesource.net:

class B // Med copy constructor
{
private:
char *name;

public:
B()
{
name = new char[20];
}

~B()
{
delete name[];
}

// Copy constructor
B(const B &b)
{
name = new char[20];
strcpy(name, b.name);
}
};
name är en dynamiskt allokerad variabel, kommer vi att behöva den explicita konstruktorn för att kopiering av klassen ska utföras korrekt.

Slutsats
Detta var ett litet urval på egenheter med C++. Nästa inlägg kommer att handla om mitt favorittillägg till standard C++, nämligen Boost!

torsdag 26 mars 2009

HOWTO use GTK+ with Eclipse

I found very little information on Google on how to use GTK+ 2.0 together with Eclipse and C/C++, which I recently had to do. This very small howto explains the procedure on Ubuntu.

First, if you dont have Eclipse installed, get the Eclipse tars for C/C++ development from eclipse.org. Install it and add

export PATH=$PATH:/usr/local/eclipse

to your .bashrc if you want.

Then get the libgtk and the gnome development kit:

sudo apt-get install libgtk2.0-dev
sudo apt-get install gnome-core-devel

If you are using C++ you want to get gtkmm (the C++ API for GTK+, not needed but strongly recommended):

sudo apt-get install libgtkmm-2.4-dev

Now fire up Eclipse. Create a new Managed Make C or C++ project.

GTK+ uses a lot of different include paths and libs. To facilitate development they have a nifty tool called pkg-config that generates the correct dependencies. Open up Project Properties -> C/C++ Build. Select the Tool Settings tab and then GCC C/C++ Compiler -> Miscellaneous. Append the following line to the end of "Other flags":

`pkg-config --cflags gtk+-2.0`

, if you are using the standard C API. If use are using gtkmm, instead put

`pkg-config --cflags gtkmm-2.4`

Add one of the following lines (depending if you use gtkmm or not) to GCC C/C++ Linker -> Miscellaneous -> Linker flags:

`pkg-config --libs gtk+-2.0`

or

`pkg-config --libs gtkmm-2.4`

Finished! Eclipse will now set up include paths and libraries correctly, although you will never see them in the project browser.

lördag 21 mars 2009

Från hanterad kod till C++, del 1

Detta är del 1 i några kommande inlägg som kanske skulle kunna kallas "Från hanterad kod till C++". Inläggen är skrivna för dig som mestadels jobbar med ett hanterat språk (.NET/Java etc.), men av någon anledning nu blivit tvungen att gå över till C++.

Jag upplevde detta ganska nyligen och la märke till att det var flera saker i C++ som inte alls är självklara, och som upplevs som onödigt krångliga. Ändå hade jag läst C++ på högskolan, men jag märkte att det är stor skillnad på de korta labbar man skrev där jämfört med ett stort, riktigt C++ projekt utvecklat av ett team experter.

Kod i .NET/Java tenderar att aldrig bli lika openetrerbar som C++ kod.Detta är inte någon fullständig guide i C++, utan inläggsserien pekar istället ut ett fåtal valda områden som jag tror många har svårt för, av den enkla anledningen att jag själv hade svårt med dem.

Inläggen förutsätter att du har grundläggande kunskaper i C++, tex i hur man använder include-filer och deklarerar klasser och variabler. Du bör också veta vad pekare är och hur de används. Om du har mycket mer erfarenhet än så, å andra sidan, kommer du nog tycka följande text är tämligen värdelös.

Svårigheterna med C++ jämfört med Java/.NET
Om man kommer från Java/.NET världen och bara tittar på någon annans C++ kod tänker man lätt "Det här är inte möjligt. Hur kan någonting vara så oläsbart och omständligt?." Ett bra exempel är stränghantering, som ofta tar sig groteska uttryck i C++, samt extremt långa och svårläsliga funktionsdeklarationer.

De största problemen med språket som jag ser det är följande:
  • Legacy. Då C++ även ska inkorporera C, där man kodar helt annorlunda än i C++, känns hela språket bloatat med funktionalitet och operatorer som man i modernare språk inte behöver. Det har dessutom hunnit komma ut en rad med överlappande frameworks, och varje utvecklare har sina egna favoritfunktioner,
  • Begreppsförvirring. Det finns många riktigt skumma operatorer och keywords i C++ som kan betyda helt olika saker beroende på i vilket sammanhang de används,
  • Pekare. Även om teorin är ganska enkel blir det ofta förvirrat, vilket inte blir bättre av C++ många, mångtydiga operatorer.Vi kan börja med ett exempel. En inte helt overklig funktionsdeklaration i C++ skulle kunna se ut så här:

MYCALLCONV template <class T> inline const char* myfunc(
const int& _myvar1, T*& _myvar2,
void (*fnc)(int**)) const;

Vissa dödliga skulle kunna påstå att ovanstående deklaration är svårpenetrerad. Vi återkommer till deklarationen i slutet av inläggsserien då vi fått lite mer kött på benen angående C++ egenheter. Till att börja med ska vi titta på några av de mer icke-uppenbara sätt som pekare och referenser fungerar.

Pekare, referenser och kopior
I .NET kan man explicit deklarera pekare i ett unsafe-block, men vanligtvis behöver man inte göra det. Som bekant är allt förutom grundtyperna (int, char, bool osv) referenser (alltså pekare) i hanterad kod, och därför behöver man aldrig oroa sig om value-type eller reference-type, då man vet att vad man än skickar in i en metod så blir det en referens (undantaget grundtyperna alltså). I C++ är det inte lika enkelt. Se följande kod:

MyClass myfunc(MyClass obj)
{
obj.variable = 2;
MyClass declInFunc;
return declInFunc;
}

int main()
{
MyClass declInMain, retVal;
declInMain.variable = 1;
retVal = myfunc(declInMain);
return 0;
}

För det första. Efter anropen i main kommer inte declInMain.variable att ha ändrats, den kommer att vara 1. Det beror på att så fort man skickar en klass/variabel in i en funktion så anropas först klassens s.k copy-constructor, som objektet. Man kan deklarera en copy-constructor explicit, men vanligtvis klarar man sig med en implicit variant som kompilatorn alltid genererar (mer om detta senare).

För det andra. Ni som kan C skulle säga att declInFunc och retVal kommer att innehålla ett odefinierat värde, då scopet slutar där myfunc slutar. Igen så använder C++ automatiskt en copy-constructor för returvärden, så retVal kommer att innehålla vad vi förväntar oss. Mycket praktiskt.

I Java/.NET kan man skriva likadant utan att declInFunc pekar på något ogiltigt, men av en annan anledning, nämligen den automatiska minneshanteraren. Om vi istället vill att declInMain skulle ändras i funktionen (alltså vara en referens) kan vi t ex definiera funktionen så här istället:

MyClass myfunc(MyClass &obj);

Nu behandlas obj som en referens istället, vilket i Java/.NET är standardsättet att skicka parametrar på. Notera att &-tecknet lätt kan blandas ihop med dereferreringsoperatorn för pekare, ytterligare en onödigt förvirrade detalj i C++. Man kan självklart också uppnå samma sak genom att skicka in en vanlig pekare i funktionen:

MyClass myfunc(MyClass *obj)

men detta kräver att parametern man skickar in är en pekare. Ibland är det bra att skicka en parameter som referens, även fast funktionen inte alls tänker ändra på parametern. Detta beror på att copy-constructorn inte anropas då man skickar en referens, och copy-construtorn kan vara långsam för stora klasser.

new/delete
En annan egenhet är nyckelordet new i C++, som inte är exakt samma sak som new i Java/.NET. Jag har läst flera böcker och guider på Internet som misslyckas med att förklara precis vad new är bra för, så låt mig också misslyckas. Jämför dessa kodsnuttar:

void func()
{
BigClass obj;
...
}

void func2()
{
BigClass* obj = new BigClass(”inargument”);

delete obj;
}

I första fallet deklareras obj på stacken, och objektet kommer alltså att förstöras och minnet frigöras då funktionen avslutas. BigClass konstruktor kommer att anropas, men utan möjlighet att ge några argument till konstruktorn. I .NET/Java världen skulle obj varit oinitsialiserad efter detta, men icke så i C++ alltså, där konstruktorn kallas automatiskt.

I andra fallet deklareras obj på heapen genom att vi använder new, och vi måste explicit frigöra minnet med ett delete-anrop inom samma scope, annars uppstår en minnesläcka.

Varför göra som i exempel 2 och använda new/delete? För det första så är det inte lämpligt att deklarera stora objekt (t ex bilder eller stora listor) på stacken. Stacken har en begränsad storlek och deklarerar man för mycket minne får man det klassiska felet "stack overflow". Heapen å andra sidan växer då det behövs och begränsas egentligen bara av tillgängligt arbetsminne.

För det andra används new då man vill deklarera en array som man inte vet storleken på vid kompileringstid.

Det är det enda man behöver komma ihåg om new/delete. I modern C++ använder man sig dock alltid av automatiska pekare som har automatisk minneshantering tillagt, ungefär som för hanterad kod. Mer om detta i senare delar.

Som en not till C användare är new samma anrop som malloc(), förutom att man också har möjligheten att skicka med argument till konstruktorn.

ref-to-ptr
Man ser ofta följande deklaration i lite större projekt:

void myfunc(MyClass *&obj);

Detta ser ju inte så trevligt ut. Uttrycket betyder att man skickar in en referens till en pekare, och detta måste man göra om man vill modifiera själva pekaren inne i funktionen (alltså inte värdet som pekaren pekar på). Om man istället bara använder:

void myfunc(MyClass *obj);

int main()
{
MyClass* inParam = new MyClass();
myfunc(inParam);
}

så går det visserligen bra att göra ändringar i obj i myfunc som slår igenom till det inskickade inParam objektet. Men om man i myfunc försöker få obj att peka på ett helt annat objekt (alltså en annan minnesadress) kommer detta inte att slå igenom, då själva pekaren kopieras vid funktionsanropet (via vår kära copy-konstruktor).

Man kan uppnå samma funktionalitet genom att använda ett så kallat ptr-to-ptr uttryck, alltså

void myfunc(MyClass **obj);

Jag föredrar dock att alltid använda ref-to-ptr, då den sistnämnda deklarationen lätt kan förväxlas med en flerdimensionell array.

Slutsats
Detta var det jag på direkten kunde komma på angående pekare och new som för mig kändes krångligast just då man tittade på kollegornas kod. Nästa inlägg kommer att handla mer om speciella egenheter med C++ och den uppsjö av keywords som språket innehåller.