Category: C

A mini-project- SDL toolkit

A mini-project- SDL toolkit

Coloured Rectangles
Image by Gerd Altmann from Pixabay

I’ve thought about doing this for a while. Build a small toolkit (a library) of helper routines for any program that uses the SDL2 library. That means it will have functions to do the following:

  1. Draw horizontal and vertical lines in a specified colour.
  2. Draw coloured rectangles both filled in and empty.
  3. Draw Circles of specified radius and colour.
  4. Draw hexagons in either orientation and of a specified size, hollow or filled.

Plus any other things that occur to me. I’ll start on this shortly.

Games in C on GitHub

Games in C on GitHub

Tetris lamp
Image by Tobias Kozlowski from Pixabay

If you visit this site often, you’ll find many many links to projects on GitHub and not just mine. One of the thing I like about GitHub is how easy it is to search for stuff. So I put games in the top left search box and then ticked the C checkbox.

That returned 2,569 results but not all are playable games. Some are one off projects for other hardware such as Wii, GameBoy, Switch and similar. One gem I found was BSDGames. This is quite old and the 43 games are text based including the original Adventure.  I get the feeling many of these are from the Basic Computer Games books but at least these are in C not BASIC.

These will probably compile better on Linux and with difficulty and lots of fixes on Windows. And yes there is a Tetris game in the collection!

 

DungeonRush – open source C + SDL 2 game

DungeonRush – open source C + SDL 2 game

DungeonRush gameI continue my quest, looking around for open source games in C that use SDL 2. The latest one is DungeonRush by developer Rapiz1 (does no one ever use their real names these days?) who hails from Wuhan.

It is not a rogue-like, but more a Snake-like game.   You move your hero around the playing area avoiding monsters and things fired at you while picking up stuff and people to give you extra lives.  As well as the difficulty levels it includes multiplayer mode as well though I haven’t tried that.

If you are learning C or games programming, it’s worth studying to see how others do things; this includes its own text drawing and high scoring and saving high scores.  It’s quite fun to play though I am rubbish playing it, even at the normal level. I’ve added this to the C Code links page. (Accessed on the top menu),

Snake games are interesting because if you use a circular buffer, no matter how big the snake grows, you can move it by just moving the head and tail elements. An O(1) operation!

Handle with care – C programming

Handle with care – C programming

Warning sign
Image by Clker-Free-Vector-Images from Pixabay

If you had programmed in say BASIC before learning C then you’d be used to a world where the worst that could happen might be a divide-by-zero crash or a hang-up due to an infinite loop. But comes to C and it has a whole raft of undefined and unexpceted behaviours.

Just how big is that list of undefined behaviours? Would you believe 193? A developer with the user name Earnestly on GitHub has compiled a list of 193 undefined behaviours. MInd you, it came from a 2007 draft C99 specification which you can find here. Note, if you scroll up a bit you can also find a list of unexpected behaviours such as what happens when you call malloc with 0 as a parameter.

Even more interesting take a look at 5.2.4.1 Translation limits which is a list of maximums in the document. Such as 1023 cases in a switch statement. or 127 nesting levels of blocks or 63 nesting levels of conditional inclusion. If you’ve ever wondered how nested #include files can go, it turns out it’s 15.

I wouldn’t bother trying to learn all the undefined or unexpected behaviours. You just have to know how to write code that doesn’t make any assumptions for instance when a signed int overflows what happens? Or if you add an unsigned int to a signed int? Best if you can, not doing these things in the first place. If you do, it might work ok for you on your computer but if someone else runs it on a different system. it may behave quite differently.

 

Tutorial 14 on working with strings published

Tutorial 14 on working with strings published

Code listing on screen with keyboard
Image by Markus Spiske from Pixabay

Reading the C reddit most days, I see from time to time question about strings. They’re not particularly complex but I feel you really have to get your head around pointers to grok strings. I’ve already done a C tutorial on Pointers and c-strings but I thought showing some examples of doing things with c-strings would not go amiss.

The pointers aspect of C strings probably muddies the water a bit. All you are doing is manipulating a contiguous block of characters in RAM that ends with a 0. The pointer just tells you where in RAM that block begins. So long as it finishes with a 0 (\0 in C), it will work ok.

That’s what Tutorial 14- working with strings is about.  Especially for beginners, doing things like converting ints to strings, or concatenating strings can be a bit fiddly. I’ve also provided both the Windows and Linux versions. i.e. compiling with Visual C on Windows and clang on Ubuntu.

For instance, you might have heard about the long to ascii function ltoa. Bad news. It doesn’t exist in Linux compilers.  There is a Windows version with the instantly memorable (not) name _ltoa_s, which is one of the safe C functions.  Incidentally if you are using SDL then there is a SDL_ltoa function provided for you although oddly it’s not documented.

So I timed a short program with /Gd and /Gr

So I timed a short program with /Gd and /Gr

StopWatch timings
Image by Michal Jarmoluk from Pixabay

This was the follow up to yesterday’s post about seeing if changing the function calling convention, switching from stacked parameters to passing them in registers made a difference in execution time.

This was the program I used.

#include <stdio.h>
#include "hr_time.h"

int add(int a, int b, int c,int d,int e) {
	return a - b * 2 + c * 3 + d * 3 + e * 5;
}

int __cdecl main() {
	int total=0;
	stopWatch s;
	startTimer(&s);
	for (int i = 0; i < 10000000; i++) {
		total += add(i, 5, 6, i, 8);
	}
	stopTimer(&s);
	printf("Value = %d Time = %7f.5\n",total, getElapsedTime(&s));
}

Pretty similar to the one I did yesterday except with two more parameters in the add function and my Windows high-res timing code. I’ve extracted the two timing files (hr_time.h/.c) from the asteroids and it’s in the LearnC folder on GiHhub.

As before this was compiled as x86. Also I tried it first compiled as release. This means the optimizing compiler has its way and I got virtually identical for cdecl (/Gd), fastcall (/Gr) and even safecall (/Gz).

Disassembly of the machine code revealed that the optimizer had moved the function code inline in the for loop and this negated the call code. So I did it again in debug mode. Here there was a clear difference. The times for fastcall were 0.259 while the cdecl (the default) was 0.239 which is about an 8% speed increase. Safecall was roughly the same execution as cdecl. So the lesson seem to be don’t use fastcall.

I think I need a more complicated program which should be compiled in release mode but where optimization doesn’t transform the function into inline code. Perhaps making the function longer would do it so the function machine code would be too long to fit in a L1 cache.

Interestingly the release code execution time was 0.005557 seconds, almost 50 x faster than the debug time.

How much faster is C code compiled with fastcall?

How much faster is C code compiled with fastcall?

Setting fastcall in VS 2019Something I read about the other day was the __fastcall convention. In Visual Studio you enable this with the /Gr flag and in gcc (it’s __attribute__((fastcall)). For clang it’s fastcall but see this.

So what does fastcall do? It changes the calling convention, so instead of pushing parameters to a function on the stack, it passes them in the registers starting with ECX then EDX and so on.  Let’s look at an example.

#include <stdio.h>

int add(int a, int b, int c) {
	return a + b * 2 + c * 3;
}

int main() {
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
}

This is the disassembly code from VS 2019. I pressed F10 to start debugging then Debug => Windows => Disassembly to get the listing. Note thei is x86, ie 32-bit.

005B18DC  lea         edi,[ebp-0C0h]  
005B18E2  mov         ecx,30h  
005B18E7  mov         eax,0CCCCCCCCh  
005B18EC  rep stos    dword ptr es:[edi]  
005B18EE  mov         ecx,offset _9831A1D6_test@c (05BC003h)  
005B18F3  call        @__CheckForDebuggerJustMyCode@4 (05B131Bh)  
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
005B18F8  push        6  
005B18FA  push        5  
005B18FC  push        4  
005B18FE  call        _add (05B1023h)  
005B1903  add         esp,0Ch  
005B1906  push        eax  
005B1907  push        offset string "Add(4,5,6)=%d\n" (05B7B30h)  
005B190C  call        _printf (05B10D2h)  

Now if I build it after setting the /Gr flag. In Vs 2019, on the project property pages, click advanced then the Calling Convention and switch from cdecl (/Gd) to –fastcall (/Gr).

008118EC  lea         edi,[ebp-0C0h]  
008118F2  mov         ecx,30h  
008118F7  mov         eax,0CCCCCCCCh  
008118FC  rep stos    dword ptr es:[edi]  
008118FE  mov         ecx,offset _9831A1D6_test@c (081C003h)  
00811903  call        @__CheckForDebuggerJustMyCode@4 (081131Bh)  
	printf("Add(4,5,6)=%d\n", add(4, 5, 6));
00811908  push        6  
0081190A  mov         edx,5  
0081190F  mov         ecx,4  
00811914  call        @add@12 (0811276h)  
00811919  push        eax  
0081191A  push        offset string "Add(4,5,6)=%d\n" (0817B30h)  
0081191F  call        _printf (08110CDh) 

I’ve highlighted the differences in bold. However the function Add is also different as the fastcall version doesn’t have to pop parameters off the stack.

Note, to get this to compile I had to prefix main with __cdecl. Using /Gr means that every function in the program uses registers and that’s not allowed with main as it’s called from Windows end must use the cdecl (default stack passing) convention.

This is what main looks like now.

int __cdecl main() {

Notes

This is only for 32-bit. 64-bit code is done somewhat differently so possibly wouldn’t be that different. Next I have to write a program that does lots of function calls and use high precision timing to see how much of a difference it makes. To be continued.

C Tutorial thirteen published on allocating memory

C Tutorial thirteen published on allocating memory

Memory chips
Image by PublicDomainPictures from Pixabay

I’ve restricted this tutorial to using malloc as it’s the main way you allocate and use dynamic memory in the thirteenth tutorial.

Pointers hold an address (of somewhere in RAM) and this can be an existing variable, a function or even data like a text string. But if you want to reserve a block of RAM and get a pointer to it, you have to call the stdlib function malloc(). (Or calloc, but I will return to that in a future tutorial).

Of course once you’ve finished using a block of RAM, it’s only polite to return it to the operating system by calling free(). Don’t forget either that malloc always returns a void * pointer, so you should cast it to something appropriate.

 

C Tutorial twelve on function pointers published

C Tutorial twelve on function pointers published

Lots of pointers
Image by pencil parker from Pixabay

While function pointers are important. I don’t think they’re quite as important as pointers. C would just not be C without pointers. There are so many things that you would not be able to do if the language lacked pointers. Things like most data structures (try doing a linked list without pointers!) .

However function pointers give additional flexibility. You can pass them as parameters in functions and store them in variables.

These are the earlier tutorials on pointers:

And this is the new one: