[Learn] Programming language: C

Tips

Having an array of functions:

					typedef void read_overhead_test_func(read_params *Params, repetition_tester *Tester);
						
					struct test_function
					{
						char const *Name;
						read_overhead_test_func *Func;
					};


					

Directly return a value from a for loop

You can do cleaner code by using this fact.

            int result = 0;
            for(;;)
            {
              if(true) return resul;
            }
            return result; // can be skipped by the if
          

Type casting seem dangerous

I have experienced a bug (sound) where I wanted to put negative and positive value in a variable of type uint32. Of course I have overflowed it. Compiler didn't catch it even with explicit -X. I have to be focused when doing code in C because it could yield in hours of debugging.

Shortcut to create a struct and some of its properties like high level programming languag

              EntityTemplateParams p =
              {
                .pos = Add3F32(params->pos, V3F32(0, 0, 2.5f)),
                .half_extents = V3F32(1, 1, 1),
                .initial_count = 8,
                .hair_index = 1,
                .ingredient_kind = IngredientKind_Wood,
              };
            

bitwise shift behave according to its type

>> on a signed value will produce 1 the reverse is true on a unsigned
It's because of the signed/unsigned shift instruction

Functions parameters

If you pass a struct directly in a parameter, it does not modify what's inside it. You have to pass the pointer of the struct in order to really update the data inside it. One way to not passing a pointer and modify it is by returning the struct from the function and use the return in the code.

For loop index initialization

if you don't initialize your index in the for's loop parameters, it will do it for you (meaning = 0)

Always initialize your for loop index.

Imagine you have two for loop one after the other (the second outside of the first). You use the same name for both of the for loop's index.
the index of the second loop will have the value of wathever was in the first.

Trick to replace you own function if other doesn&t exist

[YT] Casey Handmade Hero day 006
YAKVI explain it better [YT] Handmade Hero 021

Place of ++ does not always matter

The place of a ++ does not matter if you have no assignment. But does when you write ++Index = 2 * Index and Index++ = 2 * Index

Bit Tricks

create a masking bit from a number

If you need to bit mask the size of a number like : 1.048.576 you can by having a common number. If you use a value in order to create a number like create a memory size to malloc(SizePow), you will be able to create a mask for the number with Mask = (1 << SizePow) - 1 the -1 is important because you will switch all bit to 1 because of the way bit number works.
1 << SizePow is advancing the bit 1 count to much and when you -1 you will toggle the 1 to zero and the others to 1.

Multiply by 10

not sure, seems wrong

X << 4

Bitwise to create a 32 bits value (byte) with only two 8 bits values.

With programming language implementing bitwise operations, you can do : word = (byte1 << 8) | byte2;

The only reason why you get a 32bits from two 8 bits is because the variable IS a 32 bits value. Bitwise, so the compiler make the assumption here. operators permit to incorporate them together. You absolutely need the << to move the byte1 value aside and not be overwrited by byte2

Using a bitwise shift operation count to produce a mask

I was watching [YT] Handmade Hero 033 - 'Q&A'

Basically when you have a memory having separate chunks of data, let's say two for easier example, for the upper part you just shift X bits to the right and the upper part stay. Then, in order to use the same X value to isolate the lower part, you have to :
1. You Shift to the left the X time the number 1. You will have X zero on the lower part.
2. You substract 1 from it and as binary mathematics do, you will have X one on the right. Note that it will invert every number (as binary does).
it looks like :

						int ShiftAmount = 8;
						int Mask = 1 << ShiftAmount; // id est 0010000
						Mask = Mask - 1 // 0001111 
					

Make a 'note' class style?

The amount of bits shifted will be 0.

C Compiler didn't catch type

I don't know why but in Windows Direct Sound API I had:

							
								VOID *Region1;
								function(&Region1);
							
							it didn't catch that I was doing wrong. Indeed why would I need to & a pointer? @to-learn
						

Not casting can gives you error

I was trying to double a = int / int; and as the result had digit after the comma, it was always 0. The compiler can't tell you that because in C you do always theses type of casting, as there is no force on the way we write code, if you don't pay attention, you can have the wrong value in your variables.

Chronology of statements

Compilation Chronology

Union in C / C++

Union permit you to access a same piece of data in multiple way. id est two different structs and one type (see video). Handmade Hero - Day 014 - Union inside a struct
Handmade Hero - day 13

What are Intrinsic

Intrinsic is a way in C to call a CPU's instruction set.

Unions

OOP Rant - "how I use Unions"- Shawn McGrath

@To-Learn: [Wikipedia] Discriminated unions & auto keyword

they offer fixed size for every "objects".
you can do the following and Casey Muratori this the same thing in union-in-struct :

					struct {
						int X;
						int Y;
						union {
							struct {
								int health;
							} Player;
							struct  {
								int length;
							} Tree;
 						}
					}
				

Conditional propertie on a type without coding logic

union makes free computations (at compilation time) and conditional properties on struct

				
					enum operand_type
					{
						Operand_Address,
						Operand_Register,
						Operand_Immediate
					};
					struct instruction_operand
					{
						operand_type Type;
						union {
							effective_address_expression Address;
							register_access Register;
							immediate Immediate;
						};
					};
				

If Type is set to Operand_Address, the Address member of the union will be valid, and you can access it as instruction_operand.Address. Similarly, if Type is set to Operand_Register, the Register member will be valid and can be accessed as instruction_operand.Register. If Type is set to Operand_Immediate, the Immediate member will be valid and can be accessed as instruction_operand.Immediate.

Pass Array but not specified it in functions

You can create a struct with array inside it then just type the parameters with the struct having array inside it.

						struct game_input
						{	
							game_controller_input Controllers[4];
						};
					
						internal void GameUpdateAndRender(game_input *Input)
					
						GameUpdateAndRender(game_input *Input)
						{
							game_controller_input *Input0 = &Input->Controllers[0];    
						}
					

Macro for fucntions used multiple times

This trick is used when you want a function called multiple times and don't want to change parameters in multiple location. [YT] Handmade Hero - 021

A return in a for loop, will break it

And more ...

						for(int ControllerIndex = 0;
						ControllerIndex < ControllerCount;
						++ControllerIndex
					)
					{
						game_controller_input *Controller = GetController(Input, ControllerIndex);
						if(!Controller->IsConnected) return; // stop looping when it's true;
					}   
					

Substracting two char* will make a int64 result

 
						CatString(FullEXEPath - EXEFileName)
					
Gives compilation error:
						C2664: 'char *CatString(char *,char *)': cannot convert argument 1 from '__int64' to 'char *'
						

build.bat

Iterate on a char *[]

	
					for(char *Scan = EXEFilePath;
					*Scan;
					++Scan)
					{
					}
					

A char* can stop before you think when using string

char *SourceCodeTempDLLFileName = "handmade_temp.dll"; will give "handmade"

You have to use char SourceCodeTempDLLFileName[] instead to avoid it.

sizeof() with array

if you use sizeof(char String[] = "foo") it will include the \0. so you will often do a -1.

Separate correctly your code makes life so much easier.

Having a master memory dictate all others, meaning you have a pointer to the main memory block and have a second data type pointing to a part of this memory, will makes everything easier later.
You could have the main memory reloaded from a file and update all your game without causing a crash somewhere or having complex code that could handle this change: You just update One memory chunk and have all your data updated.
This is something to keep in mind for all projects, always try to separate the code that handle the transformation of your data and the code that update the inputs serve to it.
Handmade Hero - 024 - "Can we go over really fast an overview of the game recording code?"

How it packs array entries

[9][16]: [16] is packed contiguously while [9] will be rows.

More C unsafyness

I wrote a procedure to convert a real32 to an int32. When I was calling it in my code I did uint32 x = Procedure(real32). When real32 was negative it just wrapped around from the min value to max value. I have some warnings turned off, it should be why I had no warning about it. warnings turned of: -wd4505 -wd4101 -wd4201 -wd4100

int is more difficult to handle

Indeed it's platform dependent. Using stdint is safer. [YT] Handmade Hero 029 - 'Question: So int32 is because you want to make the game for 32bit computers?'

Having the count of the array in a struct

Usually a good thing to have it, because it permit you to track the number of data type when having an array inside it. C doesn't provide a way to get the informations (malloc() seems to do it but allocate more space than needed), so you have to implement it. I don't think it's bad, when your mind does it automatically, that's fine. Of course you add open doors to get a special bug if you don't set it correctly, but as far as I know, these bugs are easily traced.

						struct tile_map {
							uint32 *Tiles;
						};

						struct world_map {
							int TileMapCountX;
							int TileMapCountY
							tile_map *TileMaps;
						};

						{
							world_map World = {};
							World.TileMapCountX = 2; 
							World.TileMapCountX = 1; 
							// meaning TileMaps[1][2]	
						}
					
The thing to keep in mind is that you can't do a TileMaps[0][0] because C doesn't interpret it as an array, even if arrays are memory address. The cleaner way to do it is by creating an array of the actual data type in the struct, then save the address of the first entry of the array:
						tile_map TileMap00 = {};
						TileMaps[0][0] = TileMap00;
						world_map World = {};
						World.TileMaps = &TileMaps[0][0];
					

When you have typed the pointer, you can just do a Tiles[2] to retrieve the correct data, you're ensure you will always be at the right boundaries and have a proper data, wich would be dramatic if you did as C doesn't ensure the data inside the pointer is the beginning of the type. C is famous to not be safe, it's you as a developer to be aware of the code you produce.

@TODO: The reason for the count seem to not be to know the boundary of the array, instead it seems that it's a way to safely iterate on them later. The crucial part is more by first create the array of the data type then store the memory of the first entry

Avoid set all properties of a struct initialization

Sometimes you can take advantage of the fact that you can copy a previous struct data then override the properties that are different. It gives you an automatic update when updating the original data type.

Negative float truncation

If you truncate a negative float, it will [YT] Handmade Hero 0 - 'truncate towards 0'. So you have different behaviour depending if you're positive or negative. If your logic use the truncation behaviour and can have negative value, you should use floorf()

inline can be used to remind you that a function should be inline in the future.

inline is not necessary done by the compiler, so it can be just a reminder

Pass multiple struct's properties

If you pass specific struct's properties to a function as pointer, you can modify it in the function. It seems to be a good practice. Will see.

Writing functions like a_function_name() and your type like a_type gives you benefit when changing name

I had to change a struct named position and wanted to rename it to tile_map_position and using my replace all occurences from the file every functions named like get_position() where renamed like get_tile_map_position().

Using underscore and only lower case characters when naming function(s) and struct(s) make easy renaming when not using a bloated IDE.

Use another struct to "automatically allocate memory"

I was watching [YT] Handmade Hero 032

If you have an allocated amount of memory initialized by the OS (like a game state) and you know its address in memory, storing data inside it is a pain because you will have to deduce the memory of the last address it was written + the size it was. In order to do it automatically there is an easy trick

struct inside the game state previously allocated in memory:
					struct memory_arena {
						uint8* Base;
						memory_index Size;
						memory_index Used;
					};
				

A function to initialize it in order to keep track of it later

					internal void
					initilialize_arena(memory_arena *Arena, memory_index Size, uint8* Base)
					{
						Arena->Base = Base;
						Arena->Size = Size;
						Arena->Used = 0;
					}
				

A function to add memory on the next chunk memory

			
					#define push_struct(Arena, type) (type*)push_size_(Arena, sizeof(type))
					#define push_array(Arena, Count, type) (type*)push_size_(Arena, (Count)*sizeof(type))
					void*
					push_size_(memory_arena *Arena, memory_index Size)
					{
						Assert(Arena->Used + Size <= Arena->Size);
						void *Result = Arena->Base + Arena->Used;
						Arena->Used += Size;
						return(Result);
					}
				

Create macro to handle "generic" code

I was watching [YT] Handmade Hero 034 - 'Size type'

When you want to handle a parameter that is a struct there is no way to make it work normally, as in any programming language I know of. But see C/C++ permits you to use macros in order to do it.

					#define push_struct(Arena, Type) (Type*)push_struct_(Arena, sizeof(Type))
					void*
					push_struct_(memory_arena *Arena, memory_index Size)
					{
					}
				

Don't expect to have memory size initialized for arrays in your struct

I was wondering: I initiazed a struct that had tile_chunk *TileChunks inside it, I was using for loop in order to set the specific tile_chunk items inside it. Do I need to first do something like passing an array I had created in the pointer? In order to initialize it. The answer is yes. If you never explicitely point the pointer to an actual memory size (so an explicit array) the compiler will never knows the size he has to allow. Then you will have a null pointer exception when you will try to write in the X (>0) item.

If you have a struct that has an array inside it, the amount of memory needed for them is not initialized. It seems obvious when you think at first about it, but when you're inexperimented and don't have the automatism, you will easily forget to initialize an array. The reason is that you don't declare an array but a pointer to the array. The compiler has no clue on the size you will require. Some programming languages force you to assum a size and if you want to extend it they will ask you to call a method. It's called "dynamic array" and you can implement the behaviour in C. The better way to do it is by copying stb lib from Sean Barret and the stb_ds.h file

When to use #define over const?

I was watching [YT] Handmade Hero 035 - 'When do you use #define instead of local variables?'

#define gives you the benefit to not have a type. So you will be able to use it in several places.

Why prefer bool32 over bool native type?

I was watching [YT] Handmade Hero 035 - 'Why suffix types with 32 such as bool32?'

C convert bool type to true/false and have performance cost.

Using struct's properties to read adjacent bits

[YT] Handmade Hero 036 - 'Packing a struct to avoid padding'

Arena: Variable section width in file format (align 1)

            I discovered another great use for arenas: writing custom file formats with variable length sections.
            If you make an arena and set the align to 1, you can just use that arena to build your file without having to do as much pointer arithmetic.
            Say you have a section that is 

            struct section
            {
              size_t size;
              HeaderType type;
              // Section Specific data starts here
            };

            You can construct an arena, then just push that struct and push the data afterwards.
            You can of course do the same with using plain old fwrite, but then it is harder to debug in the debugger. With arenas you can check in memory easier and you get all the other benefits of the arena.
            Once you have built the whole thing in memory you can just dump it into a file 
            Yep this is similar to what the PDB -> RADDBGI converter does
            https://github.com/EpicGamesExt/raddebugger/blob/dev/src/raddbgi_from_pdb/raddbgi_from_pdb.c#L3762
        

C++ does not use the order of the "properties" to pack bits. It pack bits depending on the bit boundaries of the highest amount of bits in the struct You will have to guide C to #pragma pack from [Microsoft] pragma pack. It's like a stack, you #pragma pack(push,1) and declare your struct, then you #pragma pack(pop) when you're done.

You can either do it with the compiler. But as you don't do it often and there's is no difference, it's fine. Does it apply only with Windows?

Data types are just a cast

I had a realization when I was processing a bitmap and reading the content from it: Before having created a type bitmap_header I was just casting the content in the watch window of the debugger. Then when I created the data type then casted with it the content in my C code, I could read all properties nicely. You feel dumb when you realize simple things like it but it's just a way for you to quicker make sense of a memory in the computer, nothing more. I'm pretty sure you could never have to create a data type in your code and be able to do the same computation.

Data types are just a way to nicely make sense of the computer's memory content.

Some reasons why templates are bad to be used

[YT] Handmade Hero 036 - 'Why wouldn't you use a function template in the example mentioned before?'

Template have been created in order to minimize the amount of lines of code you need to write in similar situations. If your program always do the same operations maybe that's an ok situation to be used. But writing lines of code is not hard, your compiler will have better time to optimize it, you will understand easily what a function does and I don't think maintanability is actually gain from it, we have code editors that can handle macros, have powerfull replace function.
Meta programming is a better solution (C/C++ are bad at it though)

CPU's bit manipulation

[YT] Handmade Hero 037 - 'Bitscan forward'

[Wikipedia] Bit scan manipulation and _BitScanForward, _BitScanForward64

The reason why you need to set meanings to the static keyword

[YT] Handmade Hero 040 - 'The reasoning behind internal, local_persist, and global_variable'

Having different meaning depending of where it is used, you need to be able to produce a grep adequate, as your source code becoming large.

Preprocessors

Useful ressources

Explanation of the possibilities of preprocessors https://learn.microsoft.com/en-us/cpp/preprocessor/grammar-summary-c-cpp?view=msvc-170
The website gives you very detailed explanation of preprocessing in C/C++

#include trick

As it's like a copy / paste thing you can do a cool thing like fill an array with another file generated from a build like:

							static instruction_encoding InstructionTable8086[] =
							{
								#include "sim86_instruction_table.inl" // file created by a previous compilation
							};
						

Some tricks of preprocessors

Variadic Macros

Variadic macros
Defining function macros with variable number of argument:

						#define eprintf(...) fprintf (stderr, __VA_ARGS__)
					

use:

						eprintf ("%s:%d: ", input_file, lineno);
					

Compiled as:

						fprintf (stderr, "%s:%d: ", input_file, lineno);
					

Functions

By references / by value

  1. by value: When parameter is a data type, the value of the data type passed is copied into the call stack. So when it lives the function, everything is discarded.
    It's a very good thing because you can use this in order to use the data inside the data type, modify it and be sure the modifications will never live the function (pure function).
  2. by reference: When parameter is a pointer to a data type, every modification is on the actual data type it passed to the function parameter.
    Perfect in order to modify a data.

Behaviour

Breaking a for loop without break

							for(u64 Index = 0; Index < A.Count; ++Index)
							{
								if(A.Data[Index] != B.Data[Index])
								{
									return false;
								}
							}
						

Memory Management

Avoid silent memory free use

Pass a memory pointer, then = {} in order to reset it and get a proper exception if used after the free

							static void FreeBuffer(buffer *Buffer)
							{
								if(Buffer->Data)
								{
									free(Buffer->Data);
								}
								*Buffer = {};
							}
						

Know the size of a file before reading it

Preprocessor permits you to do it, available in Windows and other OS

							#if _WIN32
									struct __stat64 Stat;
									_stat64(FileName, &Stat);
							#else
									struct stat Stat;
									stat(FileName, &Stat);
							#endif
						

The structure will have several properties of the file.

Unlimited nested type inside a struct

If you have a data that can have unlimited nested structures, do:

							struct json_element
							{
								buffer Label;
								buffer Value;
								json_element *FirstSubElement;
								
								json_element *NextSibling;
							};
						

Notice the pointers.
Then in order to iterate through it:

							for(json_element *Search = Object->FirstSubElement; Search; Search = Search->NextSibling)
							{}
						

Malloc is not evil

Used properly

Tracking failed memory assignement

@To-Learn: Absolutely not sure, on msvc it's right but have tried on a online c compiler and it initialize

static foo; permit to be certain that the variable is undefined then you can use the "value" for the memory variable if it fails:

							static u8 FailedMemory;
							if(!Memory)
							{
								Memory.Adress = &FailedMemory;
							}
						

Arrays

Inside struct

Don't put directly {type Array[];}, instead put a pointer {type *Array}.
You avoid a compiler errors saying you must put array at the end | you can't assigm it to a variable. You store way less data inside the type, as you only need the pointer to the array.

Print

Print directly to the screen

Using directly the pointer sterr you're to use fprintf("hello", stderr); without having to open a file handle and more.

Pointers

Point a struct property to a static string array

							static char *Raw[] = {"�", "", ""};
							struct ascii_table
							{
								char **Encodings;
								int AsciiCount;
							};
						

Difference between char and char* tables

A table char Table1[] nad char *Table2[] differ in the way it's interpreted.
A simple example permit to understand it:

								static char Table1[] = {'\0', '\};
								static char *Table2[] = {"�", "};
							

* binds to the name, not the type

[Twitter] Jonathan Blow complaining on VS formating on pointers.

							void example()
							{
								int* a,b;

								a = b;
							}
						

Gives you an error.

Naming a char pointer the same will cause bugs

I had created a char Temp[MAX_PATH]; inside a function then another one in the main.
main called the function ones. And a weird bug occured when the declaration of char Temp[MAX_PATH]; was passed inside the main.
Indeed all the data that was from the Temp from the function updated at the same time.
The reason is that when you call a function that create a data type and set it to a struct. It stays in the call stack of the program. So if you call it again.