Jump to content

General Programming Guide: Difference between revisions

From SA Docs
mNo edit summary
Line 149: Line 149:
     return value1 + value2;
     return value1 + value2;
}
}
</syntaxhighlight>There can be functions without arguments and/or without return values. If a function doesn't return a value, <code>void</code> is used, and the <code>return</code> statement is not required. Below is a function that doesn't take any arguments and doesn't return anything.<syntaxhighlight lang="cpp">
</syntaxhighlight>Functions can call other functions. There can also be functions without arguments and/or without return values. If a function doesn't return a value, <code>void</code> is used, and the <code>return</code> statement is not required. Below is a function that doesn't take any arguments, calls another function and doesn't return anything.<syntaxhighlight lang="cpp">
void PrintSomething()
void PrintSomething()
{
{

Revision as of 04:36, 4 October 2025

This guide is meant for complete beginners without prior knowledge or experience of programming in C.

Note: Some information here is only relevant in the context of creating mods, and may not apply to other programming languages or contexts. Some details and accuracy have been sacrificed for the sake of simplicity.

Comments

Comments in C are preceded by //. Everything after // on the same line will be regarded as a comment, and ignored during compilation.

You can also use /* and */ for multi-line comment blocks like this:

// This is a single-line comment

/* This is a multi-line comment.
This is the second line of the multi-line comment.
This is the last line of the multi-line comment. */

Bits and Bytes

Bits are the most basic units of information that can store a binary state: on (1) or off (0). A byte consists of eight bits, so it can store eight independent binary states.

Data Types

Values can be represented in many different ways. The Sonic Adventure games were built with Ninja SDK, which has its own names for common types in C. When you write your code, it's recommended to use the Ninja types.

Integer values can be signed or unsigned. Unsigned values have a larger range but cannot be below zero.

Non-integer values are stored with single (around 7 digits) or double (around 16-17 digits) precision.

C type Ninja type Size in bits Size in bytes Range Description Example declaration
signed char Sint8 8 1 -128 to 127 Signed 8-bit integer. Sint8 myvalue = -5;
unsigned char Uint8 8 1 0 to 255 Unsigned 8-bit integer. Uint8 myvalue = 255;
__int16 Sint16 16 2 -32768 to 32767 Signed 16-bit integer. Sint16 myvalue = -1000;
unsigned __int16 Uint16 16 2 0 to 65535 Unsigned 16-bit integer. Uint16 myvalue = 33000;
int Sint32 32 4 -2147483648 to 2147483647 Signed 32-bit integer. Sint16 myvalue = -80000;
unsigned int Uint32 32 4 0 to 4294967295 Unsigned 32-bit integer. Uint16 myvalue = 900000;
float Float 32 4 1.2E-38 to 3.4E+38 32-bit floating point with single precision. Can accommodate up to 7 digits after or before a decimal point.

Make sure to put f at the end of the value to distinguish it from double!

Float myvalue = 100.0f;
double Double 64 8 1.7E-308 to 1.7E+308 64-bit floating point with double precision. Can accommodate up to 16 to 17 digits after or before a decimal point. Double myvalue = 123.123456789;
void Void 32 4 None Indicates absence of a value. Used for pointers or to declare functions that don't return a value. void MyFunction(Uint8 argument)

{ // Code }

Note: Because of the way floating point values are stored, they cannot always be converted exactly, and you should not use exact comparisons involving float and double types. For example, 0.1f + 0.2f would not be equal to 0.3f, often you would see values such as 0.699999... instead of 0.7 etc.

Pointers

A pointer is a variable that stores the memory address of another variable. To put it simply, "pointer to 'myvalue'" means "the location of 'myvalue'".

Pointers are declared with the * operator:

Uint32 value = 80000; // Declare the value
Uint32* ptr_value = &value; // Set the pointer 'ptr_value' to the memory address of 'value'

To retrieve or modify the value referenced (pointed to) by a pointer, you need to dereference it using the * operator. To retrieve the address of the value, you can use the & operator.

Uint32 value = 80000; // Declare the value
Uint32* ptr_value = &value; // Set the pointer 'ptr_value' to the memory address of 'value'

*ptr_value = 75000; // Change 'value' from 80000 to 75000 by dereferencing the pointer.

Uint32 newvalue = *ptr_value; // Declare a new variable and set it to the value referenced by the pointer.

Uint32 address = &ptr_value; // Declare a new variable and set it to the address of the value referenced by the pointer.

In the example above, the type of the value referenced by the pointer (Uint32) is known, so the pointer is declared as Uint32*. You can also declare pointers with void* without specifying the data type. To manipulate data referenced by void pointers, you will need to cast them to other types (see below).

Casts

Type casting means converting between data types. In mods, sometimes you need to access certain data types as if they were a different type. For example, you can divide two integers to get a result with a decimal point like so:

int value1 = 5;
int value2 = 2;

float nocast = value1/value2 + 1.0f;
float cast = (float)value1/value2 + 1.0f;

// The value of 'nocast' will be 3.0f
// The value of 'cast' will be 3.5f

Casts are often used with pointers:

void* mymem = MAlloc(4)); // Calls the function MAlloc to allocate 4 bytes of memory and set the 'mymem' pointer to the location of those bytes.
Uint32* myvalptr = (Uint32*)mymem; // Declares a pointer 'myvalptr' as a pointer to an unsigned 32-bit (4-byte) integer.

Functions

A function is what makes things happen in your mod. Functions can have arguments (input) and return values (output). The function below returns a sum of two values. Its arguments are value1 and value2, both Uint32, and the return value is also Uint32.

Uint32 CalculateTwoNumber(Uint32 value1, Uint32 value2)
{
    return value1 + value2;
}

Functions can call other functions. There can also be functions without arguments and/or without return values. If a function doesn't return a value, void is used, and the return statement is not required. Below is a function that doesn't take any arguments, calls another function and doesn't return anything.

void PrintSomething()
{
    PrintDebug("This is a test");
}