Technical Documentation

Caution

We are currently writing this documentation. It may be incomplete, imprecise, use it at your own risk.

Table of contents

C Basics

Just to be sure that you still know the basics.

Types

Integers
Type Minimum Maximum Bytes
INT -2,147,483,648 2,147,483,647 4
UNSIGNED INT 0 4,294,967,295 4
LONG -9,223,372,036,854,775,808 9,223,372,036,854,775,807 8
UNSIGNED LONG 0 18,446,744,073,709,551,615 8
SHORT -32,768 32,767 2
UNSIGNED SHORT 0 65,535 2

Operators

Arithmetic Operators
Addition : +
Addition is used to add operands
int a = 10;
int b = 15;

Now a + b = 25

Bitwise Operators

Bitwise operator perfom bit-by-bit operation.

Did you just say bit-by-bit operation ?

A bit-by-bit operation is an operation that apply to each bit of a binary value.

Binary ?

Let’s take a short int as an example which value is 42.

In a computer memory, it takes 2 bytes to store our value. It will look like that

0 0 0 0 0 0 0 0  0 0 0 1 0 1 0 1

It is important to understand what a logic gate is.

Logic are used in electronic, they have inputs and an output

Look at the first gate:

AND GATE
     +-----+
A ---|     |
     |  &  |---- OUTPUT
B ---|     |
     +-----+
Inputs Output
A B A & B
0 0 0
1 0 0
0 1 0
1 1 1

The output is 1 when both of the inputs are 1

OR GATE
     +-----+
A ---|     |
     |  ≥1 |---- OUTPUT
B ---|     |
     +-----+
Inputs Output
A B A | B
0 0 0
1 0 1
0 1 1
1 1 1

The output is 1 when at least one of the inputs is 1

XOR GATE
     +-----+
A ---|     |
     |  =1 |---- OUTPUT
B ---|     |
     +-----+
Inputs Output
A B A ^ B
0 0 0
1 0 1
0 1 1
1 1 0

The output is 1 when only one of the inputs is 1

NOT GATE
     +-----+
     |     |
A ---|  1  |---- OUTPUT
     |     |
     +-----+
Inputs Output
A ~A
0 1
1 0

The output is the inverse of the inputs

Operators

Now we are going to look at bitwise operators in C

What operators do is applying logic gate to each one of bits in the variable

AND : &

AND operator apply AND gate to each bit

short int a = 10; // 00000000 00001010
short int b = 20; // 00000000 00010100

To represent the operation:

  00000000 00001010
& 00000000 00010100

  00000000 00000000

a & b = 0

OR : |

OR operator apply OR gate to each bit

short int a = 10; // 00000000 00001010
short int b = 15; // 00000000 00001111

To represent the operation:

  00000000 00001010
| 00000000 00001111

  00000000 00001111

a | b = 15

XOR : ^

XOR operator apply XOR gate to each bit

short int a = 10; // 00000000 00001010
short int b = 15; // 00000000 00001111

To represent the operation:

  00000000 00001010
^ 00000000 00001111

  00000000 00000101

a ^ b = 5

NOT : ~

NOT operator applies NOT gate to each bit

short int a = 10; // 00000000 00001010

To represent the operation:

~ 00000000 00001010

  11111111 11110101

~a = -11

Makefiles

Introduction

A Makefile is a file, read by the Make program, which executes all the commands and rules in the Makefile.

Remember

Remember the first two days of C Pool. You were supposed to use bash and build your own aliases and scripts. Make is kind of a custom build script that makes your programmer-life really easier.

At EPITECH, you’ll be using Makefiles to compile your code, using a compiler.

Generic Makefile

A simple Makefile is composed of your project source files (the .c files) and some rules to make your Make command work.

You have to list your source files like this:

SRC = ./main.c \
      ./file.c

After that, you can use them to build your objects. It will take all .c files in $(SRC) and compile them into .o files.

OBJ = $(SRC:.c=.o)

For the compilation there is a feature that allow you to compile each .c with flags, it’s the +=. For example let’s add verification of errors flags : -Werror -Wextra and a flags to find .h of your project : -I./include. You can call this variable CFLAGS for compilation’s flags.

CFLAGS += -Werror -Wextra -I./include

Be careful !

You don’t have to call this variable in your Makefile, he will solo add it to the compilation of your .c.

Now, set the name of your final binary using NAME, so the AutoGrader can find your binary correctly.

NAME = binary_name

Then, it is mandatory to create a $(NAME) rule that will execute other rules, and render a binary.

$(NAME): $(OBJ)
         gcc -o $(NAME) $(OBJ)

all:     $(NAME)

Pro-tip

When you have a rule like $(NAME), the rules put in the same line will be used as mandatory rules. After those rules have been called, the command on the next lines will be called.

For instance, this will execute the ls command without executing any previous rule.

list:
      ls

You can also have some rules that permit you to clean-up your folder without having to do it manually.

For instance, this clean will remove .o files. Also, fclean will remove .o files and the binary. re will do fclean and re-make your binary.

clean:
        rm -f $(OBJ)

fclean: clean
        rm -f $(NAME)

re:     fclean all

Don’t forget to put a .PHONY, in order to avoid relinking. Put all the rules you use.

.PHONY: all clean fclean re

And that’s pretty much it ! Your Makefile is now ready to use.

Criterion Makefile

At EPITECH, you use criterion for unit tests. In order to make it clean there is a approach given by EPITECH.

First of all, you have to add a new rule to your main Makefile, according to EPITECH this rule should be named tests_run.

Pro tip

In order to make it cleaner we recommend you to another Makefile in the tests directory and link to the main. To call a Makefile rule of your tests Makefile just type : make -C tests/ [rule_name] in your main Makefile.

The tests_run rule should compile your sources files .c and your tests files. This rule must launch your binary ./unit-tests.

Mendatory !

You never have to put your main function in the source files that you compile for unit tests : Criterion have his own.

Your tests must compile with the CFLAG --coverage (see Generic Makefile). This flag will create .gcda and .gcno of your sources files.

Tip

Make a rule to clean all your .gcda and .gcno files.

Now, when you launch your tests_run rule, your binary of tests should compile again and execute so that you can see if you passed tough your tests. You should see your files from –coverage. You can use the gcov [files] to see how many line were executed when you launch your unit tests.

Clear all .gcda, .gcno and .c.gcov and you can push it to the AutoGrader !

Library Makefile

Advanced Makefile

Criterion

Criterion is a unit-testing tool that will allow you to test your code efficiently.

Introduction

Setup

If you haven’t installed Criterion yet, please download install_Criterion.sh from the intranet, then run it. Criterion will be installed.

What is Criterion ?

Warning

Do not forget to follow the Coding Style !

Criterion lets you create a set of tests that will be executed on your code. Creating a test follows this pattern :

Test(suite_name, test_name, ...)
{
          //tests
}

The suite_name must be the name of a set of tests, which will help you know exactly what part of your code fails. The test_name is here to help you know which precise test failed, and thus will be usefull to help you debug your code.

Danger

If you want your tests to work, you must compile your code with Criterion’s library using the -lcriterion flag. You should also consider running your code with the --verbose flag if you want a full summary of the test’s results.

Asserts

Asserts are Criterion’s way of defining tests to run. You will have to define several assets in order to test every bit of your code. Let’s see an example using Criterion’s most basic assert, cr_assert. This asserts takes a condition as a parameter, and the test passes if the condition is true :

Test(basics, first_test) {
          cr_assert(1 + 1 == 2);
}

Here, as one plus one will always be equal to two, the test will always pass. Let’s see the full list of Criterion’s asserts.

Warning

All asserts are located in the header <criterion/criterion.h>. Don’t forget to include this header in order to make your tests functionnal.

Note

Most asserts here have the assert keyword in their name. You should be aware that using those macros will stop the whole test right away if they fail. If you want to run some code after the test, even if it fail, you should really consider changing assert with expect. For example, in the following code the printf function will not be executed :

Test(suite_name, test_name) {
        cr_assert(0);
        printf("I wanted to run this code :/");
}

But in this example it will still run :

Test(suite_name, test_name) {
        cr_expect(0);
        printf("I will live :D");
}
Basic asserts

Note

In addition to the condition tested by the following tests, it is possible to give a string as parameter which will be printed to stderr if the test fails. This optionnal string can take printf-like arguments. For example, you can do something like:

Test(suite_name, test_name) {
        int i = 0;
        int j = 2;
        cr_assert(i * 2 == j, "The result was %d. Expected %d", i * 2, j);
}
cr_assert(condition)

Passes if condition is true.

cr_assert_not(condition)

Passes if condition is false.

cr_assert_null(condition)
cr_assert_not_null(condition)

Passes if condition is NULL, or is not NULL.

Common asserts

Note

Please note that the following asserts only work for non-array comparison. If you want to compare arrays, please refer to cr_assert_str_eq() or cr_assert_arr_eq().

cr_assert_eq(Actual, Reference)
cr_assert_neq(Actual, Reference)

Passes if and only if Actual is equal (or not equal, if you are using neq) to Reference.

cr_assert_lt(Actual, Reference)
cr_assert_leq(Actual, Reference)

Will pass if Actual is less than (or less than or equal if you used leq) Reference.

cr_assert_gt(Actual, Reference)
cr_assert_geq(Actual, Reference)

Will pass if Actual is greater than (or greater than or equal if you used geq) Reference.

String asserts

Note

Those functions won’t allow you to compare the output of your progam with a given reference string. To do so you must use redirections. Check cr_assert_stdout_eq_str() for more info.

cr_assert_str_eq(Actual, Reference)
cr_assert_str_neq(Actual, Reference)

Just like cr_assert_eq(), but will check two strings, character by character.

cr_assert_empty(Value)
cr_assert_not_empty(Value)

Will pass if the string is empty (or is not empty is you used not_empty).

Hint

There are also str_lt, str_gt, etc… macros that will check the lexicographical values of the two sting given, just like your my_strcmp would do (if you’ve done it well :D).

Array asserts
cr_assert_arr_eq(Actual, Expected, Size)
cr_assert_arr_neq(Actual, Expected, Size)

Compares each element of Actual with each of Expected.

Caution

While not documented in Criterion’s official documentation, Size is mandatory, otherwise the test will be marked as failed.

Redirections

Tip

To use the following assertions, you must include <criterion/redirect.h> along with <criterion/criterion.h>. redirect.h allows Criterion to get the content of stdout and stderr and run asserts on it. You also need to create a function that calls the cr_redirect_stdout() function.

cr_assert_stdout_eq_str(Value)
cr_assert_stdout_neq_str(Value)

Compares the content of stdout with Value. This assertion behaves similarly to cr_assert_str_eq().

cr_assert_stderr_eq_str(Value)
cr_assert_stderr_neq_str(Value)

Compares the content of stderr (a.k.a. “error output”) with Value.

Here is a sample usage of this assert.

#include <criterion/criterion.h>
#include <criterion/redirect.h>

void redirect_all_stdout(void)
{
        cr_redirect_stdout();
        cr_redirect_stderr();
}

int error(void)
{
        write(2, "error", 5);
        return(0);
}

Test(errors, exit_code, .init=redirect_all_stdout)
{
        error();
        cr_assert_stderr_eq_str("error", "");
}

Note

Note that you MUST include criterion.h and redirect.h in this order, otherwise you tests won’t work.

Test options

Options reference

It is possible for you to provide additional parameters to a test. Here is a full list of thos parameters and what you can do with them.

.init

This parameter takes a function pointer as an argument. Criterion will execute the function just before running the test.

Note that the function pointer should be of type void (*)(void).

Here is a sample usage of this parameter.

void my_func(void)
{
        my_putstr("Here is the beginning of my test\n");
}

Test(suite_name, test_name, .init = my_func)
{
        //tests
}
.fini

This parameter takes a function pointer to a function that will be executed after the tests is finished.

It takes the same pointer type as the .init parameter, and also has the same usage.

.signal

Warning

In order to use this parameter, you must include the header <signal.h>

If a test receives a signal, it will by default be marked as a failure. However, you can expect a test to pass if a special kind of signal is received.

#include <stddef.h>
#include <signal.h>
#include <criterion/criterion.h>

Test(example, will_fail)
{
        int *ptr = NULL;
        *ptr = 42;
}

Test(example, will_pass, .signal = SIGSEGV)
{
        int *ptr = NULL;
        *ptr = 42;
}

In the above example, the first test will fail while the second one will not.

You can find a full list of handled signals by checking signal.h’s documentation here : http://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html.

.exit_code

By default, Criterion will mark a test as failed if it exits with another exit code than 0.

If you want to test your error handling, you can use the .exit_code parameter so the test will be marked as passed if the given exit code is found.

Here is a sample usage of this parameter :

#include <unistd.h>

int error(void)
{
        write(2, "error", 5);
        exit(0);
}

Test(errors, exit_code, .exit_code = 84)
{
        error();
        cr_assert_stderr_eq("error", "");
}
.disabled

If true, the test will be skipped.

.description

This parameter must be used in order to give extra definition of the test’s purpose, which can be quite helpful if your suite_name and test_name aren’t as explicit as you would like.

.timeout

This parameter takes a double, representing a duration. If your test takes longer than this duration to run, the test will be marked as failed.

Suite configuration

If you want to set a test for all of a suite’s members (for example, setting the exit code of all your error handling tests), you can, using the TestSuite macro.

#include <criterion/criterion.h>

TestSuite(suite_name, [params...]);

Test(suite_name, test_1)
{
        //tests
}

Test(suite_name, test_2)
{
        //other tests
}

As you can see, you can set some params to all the tests with the same suite_name at once.

Criterion - Upcoming assert API

Introduction

In this tutorial we will take a look at Criterion’s upcoming assert API. If you’re not familiar with Criterion, you may start with the first part of our Criterion documentation.

Setup

Before using the new assert API, it is necessary to download and build the development version of Criterion, as we are working with unreleased functionality.

Start by downloading the code with this command :

$ git clone --recursive git@github.com/Snaipe/Criterion.git

Note

Take note of the –recursive option, it is necessary to compile the code.

Once the code is downloaded, let’s build it.

$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
$ sudo make install

Now, to use any of the features described in this page, you will need to include the following headers to your test files.

#include <criterion/criterion.h>
#include <criterion/new/assert.h>

Assertions

With the old Criterion, there was a multitude of assertion functions, covering a lot of cases. This led to a few useless repetitions, such as cr_assert_eq, cr_assert_str_eq, cr_assert_arr_eq… The new API is much more straightforward, there are only 5 assertion functions :

Reference
cr_assert(Criterion)

Passes if Criterion is true, abort if not.

cr_expect(Criterion)

Passes if Criterion is true, fails if not.

Note

The difference between cr_assert and cr_expect is the behavior when the test fails. An assert will stop the test right away while an expect will continue until the end of the test.

cr_fail()

Marks the test as failed. Can be used when testing manually with conditions for example.

cr_fatal()

Marks the test as failed then abort.

cr_skip()

Marks the test as skipped then abort.

Note

All of those macros can take an optional printf-like string which will be printed if the test fails (see below for an example).

Example
Test(my_suite, my_test) {
    FILE *myfile = fopen("myfile.txt", "r");
    if (myfile == NULL) {
        cr_fatal("Test mytest failed, file could not be opened : %s\n", strerror(errno));
    } else {
        // Do something...
    }
}

Criteria

As you can see, there aren’t any macros that compare values. This new API does not expect you to write the comparison functions yourself, you may use a set of predefined Criteria (or _Criterions_) which are the recommended parameters of cr_assert and cr_expect.

Reference
Logical Criteria

Logical criteria are simple helpers to test multiple criteria at once.

not(Criterion)

Evaluates to !Criterion.

all(...)

Takes a sequence of Criteria as parameters. Will be true if all Criteria given are true. (equivalent to an &&)

any(...)

Takes a sequence of Criteria as parameters. Will be true if any Criteria given is true. (equivalent to an ||)

none(...)

A combination of a not over each criteria and an all.

Tagged Criteria

Those are the real useful testing macros.

Note

Do not worry with the following Tag parameters, the complete list of tags are described in the nex section.

General Purpose
eq(Tag, Actual, Expected)

Tests if Actual is equal to Expected.

Note

This function may only use the operator == if the tag specifies numeric values. It is also able to the the equality between strings if given the tag str.

ne(Tag, Actual, Expected)

Tests if Actual is not equal to Expected.

lt(Tag, Actual, Expected)

Tests if Actual is less than Expected.

le(Tag, Actual, Expected)

Tests if Actual is less than or equal to Expected.

gt(Tag, Actual, Expected)

Tests if Actual is greater than Expected.

ge(Tag, Actual, Expected)

Tests if Actual is greater than or equal to Expected.

Floating point

Warning

The following criteria only work with the following tags : flt, dbl and ldbl.

Epsilon

Warning

This method of comparison is more accurate when comparing two IEEE 754 floating point values that are near zero. When comparing against values that aren’t near zero, please use ieee_ulp_eq instead.

It is recommended to have Epsilon be equal to a small multiple of the type epsilon (FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON) and the input parameters.

epsilon_eq(Tag, Actual, Expected, Epsilon)

Tests if Actual is almost equal to Expected, the difference being the Epsilon value.

epsilon_ne(Tag, Actual, Expected, Epsilon)

Tests if Actual is different to Expected, the difference being more than the Epsilon value.

ULP

Warning

This method of comparison is more accurate when comparing two IEEE 754 floating point values when Expected is non-zero. When comparing against zero, please use epsilon_ne instead.

A good general-purpose value for Ulp is 4.

epsilon_eq(Tag, Actual, Expected, Epsilon)

Tests if Actual is almost equal to Expected, by being between Ulp units from each other.

epsilon_ne(Tag, Actual, Expected, Epsilon)

Tests if Actual is different to Expected, the difference being more than Ulp units from each other.

Example

All the following tests pass :

Test(strings, eq) {
    cr_assert(eq(str, "Hello", "Hello"));
}
Test(strings, ne) {
    cr_assert(ne(str, "Hello", "Hella"));
}
Test(integers, eq) {
    cr_assert(eq(int, 8, 8));
}
Test(logical, all) {
    cr_assert(all(eq(int, 8, 8), eq(str, "Hello", "Hello")));
}

Tags

The tags are Criterion-defined macros that represent standard C types.

Predefined Tags

Here is the complete list of all predefined tags :

int8_t i8
int16_t i16
int32_t i32
int64_t i64
uint8_t u8
uint16_t u16
uint32_t u32
uint64_t u64
size_t sz
void * ptr
intptr_t iptr
uintptr_t uptr
char chr
int int
unsigned int uint
long long
unsigned long ulong
unsigned long long ullong
float flt
double dbl
long double ldbl
complex double cx_dbl
complex long double cx_ldbl

See below for details about the implementation of this structure.

const char * str
const wchar_t * wcs

String of wide characters

const TCHAR * tcs

Windows character string.

Mem struct

Here is the definition of the cr_mem structure :

struct cr_mem
const void * data

data is a pointer to the data to test

size_t size

size is the size of data to test.

User-Defined Type

You can use the following macro to use you own types as Tags :

type(UserType)

You may then use you type the same way as any other tag :

cr_assert(eq(type(my_type), var1, var2));

However there are some functions to implement in order to use this type in your code.

Warning

Due to implementation restrictions, UserType must either be a structure, an union, an enum, or a typedef.

For instance, these are fine:

type(foo)
type(struct foo)

and these are not:

type(foo *)
type(int (&foo)(void))

in these cases, use a typedef to alias those types to a single-word token.

In any case

The type must be printable, and thus should implement a “to-string” operation. These functions are mandatory in any case.

C
char *cr_user_<type>_tostr(const <type> *val);

For example if you have a character type, you must implement the char *cr_mem_character_tostr(const character *val);

C++
std::ostream &operator<<(std::ostream &os, const <type> &val);
eq, ne, le, ge

These functions are mandatory in order to use the operators eq, ne, le or ge with your type. They should return 1 (or true) if the two parameters are equal, 0 (or false) otherwise.

C
int cr_user_<type>_eq(const <type> *lhs, const <type> *rhs);
C++
bool operator==(const <type> &lhs, const <type> &rhs);
lt, gt, le, ge

These functions are mandatory in order to use the operators lt, gt, le or ge with your type. They should return 1 (or true) if the first parameter is less than the second, 0 (or false) otherwise.

C
int cr_user_<type>_lt(const <type> *lhs, const <type> *rhs);
C++
bool operator<(const <type> &lhs, const <type> &rhs);

User-defined type example

#include <stdio.h>
#include <criterion/criterion.h>
#include <criterion/new/assert.h>


typedef struct vector3d {
    int x;
    int y;
    int z;
} vector3d;

/*
    Defines the string representation of a vector3d
*/
char *cr_user_vector3d_tostr(const vector3d *val)
{
    char *str = malloc(sizeof(char) * (12 + 3 * 9));

    if (str == NULL) {
        return "";
    }
    sprintf(str, "X:%d; Y:%d: Z:%d\n", val->x, val->y, val->z);
    return str;
}

/*
    Defines an equality between two vector3d
*/
int cr_user_vector3d_eq(const vector3d *lhs, const vector3d *rhs)
{
    if (lhs->x == rhs->x && lhs->y == rhs->y && lhs->z == rhs->z) {
        return 1;
    }
    return 0;
}

/*
    Creates a new vector with predefined values
*/
vector3d *create_vector(void)
{
    vector3d *vect = malloc(sizeof(vector3d));

    vect->x = 8;
    vect->y = 7;
    vect->z = 2;
    return vect;
}

Test(usertype, test) {
    vector3d *test_vect = malloc(sizeof(vector3d));
    vector3d *vect = create_vector();

    test_vect->x = 8;
    test_vect->y = 7;
    test_vect->z = 2;

    cr_assert(eq(type(vector3d), *vect, *test_vect));
}

CSFML : Graphical Programming

Table of contents

A soon-to-be complete and human-readable CSFML API reference.

Reference

Window
Window managing
sfRenderWindow

This is the most basic element of any graphic program : a window.

sfRenderWindow *sfRenderWindow_create(sfVideoMode mode, const char *title, sfUint32 style, const sfContextSettings *settings)

This function will setup a new window, based on the parameters given.

Parameters
mode:

sfVideoMode - The video mode to use (width, height and bits per pixel of the window).

title:

const char * - The title of the window.

style:

sfUint32 - You must specify at least one of the following :

  • sfNone : None of the other style options will be used.
  • sfResize : Will add a “resize” button that will allow you to change the size of the window.
  • sfClose : Will add a “close” button that will allow you to close your window.
  • sfFullscreen : Will make your window full screen.

If you want to add two or more parameters, simply separate them using pipes (see example below).

settings:

sfContextSettings * - Those are advanced render settings you can add. NULL to use default values.

Return
sfRenderWindow * - New render window.
sfRenderWindow *sfRenderWindow_createUnicode(sfVideoMode mode, const sfUint32 *title, sfUint32 style, const sfContextSettings *settings)

This function takes the same parameters as sfRenderWindow_create(), but this will take an array of integers as title, allowing you to have a unicode title.

sfVideoMode mode = {800, 600, 32};
window = sfRenderWindow_create(mode, "My awesome window", sfResize | sfClose, NULL)
void sfRenderWindow_destroy(sfRenderWindow *window)

This function allows you to destroy an existing window.

Parameter
window:sfRenderWindow * - The render window to destroy.
void sfRenderWindow_close(sfRenderWindow *window)

This function will close a render window (while not destroying it’s internal data.)

Parameter
window:sfrenderWindow * - The RenderWindow to close.
void sfRenderWindow_clear(sfRenderWindow *window, sfColor color)

This function will clear all pixels in the window, replacing them with the given color.

Parameters
window:sfRenderWindow * - The RenderWindow to clear.
color:sfColor - The color to which all pixel will change.
void sfRenderWindow_display(sfRenderWindow *window)

This function will display all sprites on screen.

Parameter
window:sfRenderWindow * - The RenderWindow to display.
Getting window data

There are a lot of data that can be obtained from a sfRenderWindow object. As I don’t want to spend my whole life writing this paragraph while knowing that no one will ever read this, I’ll only list a bunch of useful functions. I’ll probably add the others sooner or later.

sfVector2u sfRenderWindow_getSize(const sfRenderWindow *window)

This function allows you to know the size of a given render window.

Return
sfVector2u - Contains the size of the window in pixels.
sfBool sfRenderWindow_hasFocus(sfRenderWindow *window)
Return
sfBool - Will be sfTrue if the window has focus (i.e. it can receive inputs), sfFalse otherwise. This function can be useful if you want to pose your program if the window doesn’t have focus.
sfBool sfRenderWindow_isOpen(sfRenderWindow *window)

Tell whether or not a render window is open.

Return
sfBool - Will be sfTrue if the window is open, sfFalse otherwise.
Other useful options

Here are all other functions that I (Oursin) find useful for our first projects.

sfBool sfRenderWindow_pollEvent(sfRenderWindow *window, sfEvent *event)

This function will check the event queue and pop one. As such, if you want your program to take all inputs into account, it is highly advised to empty the event queue at the start of your game loop.

Parameters
window:sfRenderWindow * - The target window.
event:sfEvent * - This must take a pointer to the sfEvent object which will be filled.
Return
A sfBool will be returned, indicating whether or not an event was returned.
void sfRenderWindow_setFramerateLimit(sfRenderWindow *window, unsigned int limit)

This function allows you to set your program’s framerate.

Parameters
window:sfRenderWindow - Target render window.
limit:unsigned int - Defines the maximum number of frames your program should display each second.
void sfRenderWindow_setKeyRepeatEnabled(sfRenderWindow *window, sfBool enabled)

This function enables or disables automatic key-repeat for keydown events. If enabled, a key pressed down will create new sfEvent objects all time until it is released.

Parameters
window:sfRenderWindow - Target render window.
enabled:sfBool - sfTrue to enable, sfFalse to disable.
void sfRenderWindow_setMouseCursorVisible(sfRenderWindow *window, sfBool show)

This function allows you to hide the mouse cursor on a render window.

Parameters
window:sfRenderWindow - Target render window.
show:sfBool - sfTrue to show, sfFalse to hide.
Drawing

In CSFML, there are 4 types of objects that can be displayed, 3 of them beign ready to be used : sprites, text and shapes. The other one, vertex arrays, is designed to help you create your own drawable entities, but you would probably not use it for now.

void sfRenderWindow_drawSprite(sfRenderWindow *window, const sfSprite *sprite, sfRenderStates *states)
Parameters
window:sfRenderWindow * - The window to draw to.
sprite:sfSprite * - The sprite to draw.
states:sfRenderStates * - This can be used to use advanced render options, such as shaders, transfomations etc…
void sfRenderWindow_drawText(sfRenderWindow *window, sfText *text, sfRenderStates *states)
Parameters
window:sfRenderWindow * - The window to draw to.
sprite:sfText * - The text object to display on screen. Note that this is not a char *, but an sfText object, which must be created first.
states:sfRenderStates * - This can be used to use advanced render options, such as shaders, transfomations etc…
void sfRenderWindow_drawShape(sfRenderWindow *window, sfShape *shape, sfRenderStates *states)
Parameters
window:sfRenderWindow * - The window to draw to.
sprite:sfShape * - The shape object to display on screen.
states:sfRenderStates * - This can be used to use advanced render options, such as shaders, transfomations etc…

Examples

RenderWindow

Here is a sample example of most functions related to sfRenderWindow. For the following example, we will assume that sprite, text and shape were already created, and are variables of type sfSprite, sfText and sfShape, respectively.

We will also assume that event is of type sfEvent.

sfVideoMode mode = {1080, 720, 32};
sfRenderWindow *window;

window = sfRenderWindow_create(mode, "window", sfClose, NULL);
sfRenderWindow_setFramerateLimit(window, 60);
while (sfRenderWindow_isOpen(window) && sfRenderWindow_hasFocus
                                        (window)) {
        while (sfRenderWindow_pollEvent(window, &event)) {
                if (event.type == sfEvtClosed)
                        sfRenderWindow_close(window);
        }
        sfRenderWindow_clear(window, sfBlack);
        sfRenderWindow_drawSprite(window, sprite, NULL);
        sfRenderWindow_drawShape(window, shape, NULL);
        sfRenderWindow_drawText(window, text, NULL);
        sfRenderWindow_display(window);
}
sfRenderWindow_destroy(window);

Debug : Understanding Valgrind’s messages

Valgrind is a very useful debug tool, which happens to be already installed on EPITECH’s dump.

Introduction

What is Valgrind ?

Valgrind is an “instrumentation framework for building dynamic analysis tools”, according to Valgrind’s official documentation.

Valgrind comes with a bunch of tools, but in this page we will only focus on one of those tools : Memcheck.

Memcheck is a memory error detector. As such, it will detect and show you every memory error your code produces. It will also show you your program’s memory leaks.

How to use it ?

To use Valgrind to debug your program, you can simply add Valgrind in front of your program’s name and arguments. It should look like this

$ valgrind [valgrind\'s options] ./program [program\'s arguments]

Valgrind will now lauch your program and report any error it detects.

Valgrind’s messages

Warning

Valgrind will give you more information about where your errors come from if your code has been compiled using GCC’s -g flag.

Invalid read/write

One of the most common errors you will encounter are invalid reads or writes.

Invalid write

First, let’s write a simple C program.

int main(void)
{
        char *str = malloc(sizeof(char) * 10);
        int i = 0;

        while (i < 15) {
                str[i] = '\0';
                i = i + 1;
        }
        free(str);
        return (0);
}

Yes, this code is absolutely useless, but still, let’s compile it then run it with valgrind.

$ gcc main.c -g
$ valgrind ./a.out
==18332== Memcheck, a memory error detector
==18332== Copyright (C) 2002-2017, and GNU GPL\'d, by Julian Seward et al.
==18332== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18332== Command: ./a.out
==18332==
==18332== Invalid write of size 1
==18332==    at 0x400553: main (test.c:7)
==18332==  Address 0x521004a is 0 bytes after a block of size 10 alloc\'d
==18332==    at 0x4C2EB6B: malloc (vg_replace_malloc.c:299)
==18332==    by 0x400538: main (test.c:3)
==18332==
==18332==
==18332== HEAP SUMMARY:
==18332==     in use at exit: 0 bytes in 0 blocks
==18332==   total heap usage: 1 allocs, 1 frees, 10 bytes allocated
==18332==
==18332== All heap blocks were free'd -- no leaks are possible
==18332==
==18332== For counts of detected and suppressed errors, rerun with: -v
==18332== ERROR SUMMARY: 5 errors from 1 contexts (suppressed: 0 from 0)

So, what happened ? Well, Valgrind detected an invalid write error in our program. But what does it mean ?

“Invalid write” means that our program tries to write data in a memory zone where it shouldn’t.

But Valgrind tells you way more than that. It first tells you the size of the written data, which is 1 bytes, and corresponds to the size of a character. Then the line at 0x400553: main (test.c:7) tells you at which line your error occured. Line 7, which corresponds to str[i] = '\0'.

At the line Address 0x521004a is 0 bytes after a block of size 10 alloc\'d, it also tells you that the invalid adress is located right after a block of ten bytes allocated. What this means is that a 10 bytes (so probably 10 characters) long memory zone was allocated, but we tried to write an eleventh byte.

Invalid read

This other code will produce a Invalid read error :

int main(void)
{
        int i;
        int *ptr = NULL;

        i = *ptr;
        return (0);
}

If we compile and run this code, Valgrind will produce this error :

==26212== Invalid read of size 4
==26212==    at 0x400497: main (test.c:8)
==26212==  Address 0x0 is not stack\'d, malloc\'d or (recently) free\'d

It means that we tried to read 4 bytes, starting at adress 0x0 (for those of you who don’t know it yet, NULL is actually a pointer to adress 0x0, so we tried to read 4 bytes starting from NULL).

As before, Valgrind also tells us that the error occured at line 8 of our code, which corresponds to this instruction : i = *ptr.

Conditional jumps

Let’s create a new C program :

int main(void)
{
        int i;

        if (i == 0) {
                my_printf("Hello\n");
        }
        return (0);
}

Valgrind will produce this error :

==28042== Conditional jump or move depends on uninitialised value(s)
==28042==    at 0x4004E3: main (test.c:5)

This message may be a bit harder to understand.

Well, a jump is a computer instruction similar to a goto in C. There are several types of jumps. Some are unconditionnal, meaning the jump will always occur. Some other are conditionals, which means that the jump will be taken if a previous test was successful, and will not otherwise.

In this case, our program had a conditional jump, because one of the values that were test was not initialized, it led to unexpected behaviour. It means that the outcome of the test may change. For example it could work as intented on your computer, but could fail during the autograder’s tests.

Note

This type of error could happen if you do some tests involving a recently malloc’d block. (Note that malloc will never initialize your data).

Syscall param points to unadressable bytes

Here is our program :

int main(void)
{
        int fd = open("test", O_RDONLY);
        char *buff = malloc(sizeof(char) * 3);

        free(buff);
        read(fd, buff, 2);
}

read will try to read at the adress pointed to by buff. But this adress has already been free’d, so Valgrind will show us this error :

==32002== Syscall param read(buf) points to unaddressable byte(s)
==32002==    at 0x4F3B410: __read_nocancel (in /usr/lib64/libc-2.25.so)
==32002==    by 0x400605: main (test.c:11)
==32002==  Address 0x5210040 is 0 bytes inside a block of size 3 free\'d
==32002==    at 0x4C2FD18: free (vg_replace_malloc.c:530)
==32002==    by 0x4005EF: main (test.c:10)
==32002==  Block was alloc\'d at
==32002==    at 0x4C2EB6B: malloc (vg_replace_malloc.c:299)
==32002==    by 0x4005DF: main (test.c:8)

Here there is a lot of information that will help you debug your code. First, we know that we gave an invalid pointer to a system call, read in our case.

Then Valgrind tells us that this pointer is “0 bytes inside a block of size 3 free’d”. In fact, we allocated a 3 bytes block, then free’d it. “0 bytes inside” means that our pointer points to the very first byte of this block.

Valgrind tells us where the error occured, where the block was free’d and also where is was malloc’d.

Invalid/mismatched frees
Invalid free

Another error you may encounter is the “Invalid free” one. It means that we tried to free a pointer that cannot be free’d. Here is an example :

int main(void)
{
        char *buff = malloc(sizeof(char) * 54);

        free(buff);
        free(buff);
        return (0);
}

Yes, I agree, this error is obvious. But it does happen that the same pointer is twice free’d, or that some programmer tries to free something that wasn’t allocated. There are plenty of reasons for an invalid free to happen. Let’s look at Valgrind’s message :

==755== Invalid free() / delete / delete[] / realloc()
==755==    at 0x4C2FD18: free (vg_replace_malloc.c:530)
==755==    by 0x400554: main (test.c:10)
==755==  Address 0x5210040 is 0 bytes inside a block of size 54 free\'d
==755==    at 0x4C2FD18: free (vg_replace_malloc.c:530)
==755==    by 0x400548: main (test.c:9)
==755==  Block was alloc\'d at
==755==    at 0x4C2EB6B: malloc (vg_replace_malloc.c:299)
==755==    by 0x400538: main (test.c:7)

Valgrind tells use that there is a problem with a free, a delete, a delete[] or a realloc, but since delete is a C++ instruction, and we’re not allowed to use realloc at EPITECH, you will probably only use free.

As before, Valgrind tells us that the error occured because we tried to use free on an adress that belongs to an already free’d block.

Mismatched free

Another error you can encounter is this one :

==3073== Mismatched free() / delete / delete []
==3073==    at 0x4C2FD18: free (vg_replace_malloc.c:530)
==3073==    by 0x400613: main (in /home/oursin/a.out)
==3073==  Address 0xa09a5d0 is 0 bytes inside a block of size 368 alloc\'d
==3073==    at 0x4C2F1CA: operator new(unsigned long) (vg_replace_malloc.c:334)
==3073==    by 0x4E5AB0F: sfSprite_create (in /usr/local/lib/libc_graph_prog.so)
==3073==    by 0x400603: main (in /home/oursin/a.out)

Here, I created a CSFML sprite using sfSprite_create, then I tried to free this sprite, resulting in this error.

In fact, sfSprite_create does allocate some memory, but it does not use our dear friend malloc, but it’s C++ brother, new. And the problem is that something that has been allocated using new must be free’d using delete, not free. As delete does not exist in C, you should use CSFML’s sfSprite_destroy function.

Fishy values

The last type of error you may see is this one :

==29010== Argument 'size' of function malloc has a fishy (possibly negative) value: -1
==29010==    at 0x4C2EB6B: malloc (vg_replace_malloc.c:299)
==29010==    by 0x4004EA: main (in /home/oursin/a.out)

It simply means that you gave a impossible value to a system call. In this case I called malloc with argument -1.

Windows Activation

The magic command

For this, you need to be on the IONIS Wireless Network

Just press Windows + X, choose “Windows PowerShell (Admin)” In it, copy paste this command:

slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX

And reboot. You’re done!

WikiHow

Have you ever wondered how to properly malloc an integer variable ? Here you’ll find the answers to all your questions !

Warning

Please do not consider this page as a reliable source of knowledge. If you really believe anything here, you’re even dumber than you look.

How to malloc an int

First things first : “Why should I use malloc on an int variable ?”

To ensure you have enough space to hold every possible numeric value.

Now that this is clear, let’s speak a bit about malloc. Malloc uses a special variable type, called size_t to take its value. Usually this type of variable can be obtained by using the sizeof function. But have you ever wondered what happens if you use sizeof on the size_t type ? Yeah, you’ve guessed it. Infinity.

Now that we know that, here’s a sample code to help you create you integer that can hold infinity.

int integer = malloc(sizeof(size_t));

Warning

Do not EVER try to malloc infinity onto a void variable. DO YOU REALLY WANT TO KNOW WHAT HAPPENS WHEN YOU PUT AN INFINITY INTO NOTHING ? I do not. So please be mercyful and spare our lives.

How to set the value of all elements of an array to 42

You must be thinking “Hey, it’s useless, i’ve already malloc’d my array, and by default all elements are set to 42, why should i want this ?”.

Well, the answer is simple. You want to reset you array. Bonus point : If it is a char array, it’ll look like a hidden password when you’ll print it. And, let’s face it, that’s cool.

Now i’ll show you how to set all values to 42.

Step 1: Creating a counter variable.

You want to edit every single element of your char array, so you’ll need the help of a counter variable in order to do this.

char *my_reset_array(char *array)
{
        int i = my_strlen(array);
}

Step 2: Iterate though the array

Because you want to edit every element, you’ll need a loop structure.

char *my_reset_array(char *array)
{
        int i = my_strlen(array);

        while (i >= 0) {
                i = i - 1;
        }
}

Step 3: Edit every Value

Now all you need to do is editing all values, then returning the array.

char *my_reset_array(char *array)
{
        int i = my_strlen(array);

        while (i >= 0) {
                array[i] = 42;
                i = i - 1;
        }
        return (array);
}

Introduction

The purpose of this documentation is to help you during your EPITECH course. You will find concise documentation on main topics studied at EPITECH.

Why this documentation ?

Since EPITECH is built on DIY-learning, you may lack of precise documentation, especially if you missed some topics. This RTD is built to give you a support on which you can rely with confidence.

We really encourage people who find errors in the documentation to send us an e-mail: