development tools

GCC

source code needs to be translated to machine code:

code → pre-processor → compiler → linker

For a single module:
$ gcc -o main main.c
$ ./mainFor multiple modules:
$ gcc -c dependency.c # -> dependency.o
$ gcc -c main.c # -> main.o
$ gcc -o main main.o dependency.o # -> link together
$ ./main

Makefile

see: https://github.com/osue-tuwien/osue-tuwien.github.com/wiki/OSUE-Einführungstutorial#make

see: https://github.com/osue-tuwien/osue-tuwien.github.com/wiki/Makefile-Tutorial

Makefile s only compile files that have changed based on the given rules:

result: ingredients
recipe

Example:

void say_hello(const char *name);
#include "dependency.h"
#include <stdio.h>void say_hello(const char *name) {
printf("%s!\n", name);
}
#include "dependency.h"int main(int argc, char *argv[]) {
say_hello("Hello World");
return 0;
}

# ELF executable
main: main.o dependency.o
gcc -o dependency main.o dependency.o # -> Third: link together# object files
main.o: main.c dependency.h
gcc -c -o main.o main.c # -> Second: compile to main.ohello.o: dependency.c dependency.h
gcc -c -o dependency.o dependency.c # -> First: compile to hello.o
CC = gcc
DEFS = -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809L
CFLAGS = -Wall -g -std=c99 -pedantic $(DEFS)
LFLAGS =.PHONY: all cleanall: main# ELF executable
main: main.o dependency.o
$(CC) -o $@ $^# object files
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<main.o: main.c dependency.h
dependency.o: dependency.c dependency.hclean:
rm -rf *.o main

This makefile can be executed with: make hello , make clean

Better semantics

<stdint.h> , <inttypes.h>

standardized and portable integer types: in C a byte is just a sequential set of bits, but not necessarily 8 bits.

<stdbool.h>

true/false booleans instead of integers.

<stdlib.h>

NULL is a macro for the null pointer - which points to the address 0 which can’t be dereferenced: ((void *)0)

“NUL” does not exist. When people say “nul” they mean the ASCII character for integer 0 (‘\0’).

EXIT_SUCCESS , EXIT_FAILURE status codes

there are more status codes without these macroshttps://tldp.org/LDP/abs/html/exitcodes.html

-DDEBUG

Used for log messages

gcc ... -DDEBUG # enable debug messages with flag
#ifdef DEBUG
#include <stdio.h>
#define debug(fmt, ...) \
(void) fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define debug(ignored) /* NOP */
#endif
...
debug("reached"); // [main.c:18] reached

perror()

to wrap error messages

equivalent to: fprintf(stderr, "%s: %s\n", msg, strerror(errno));

good practice: using while-do loops for macros.

#define errorMsg(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)

Man pages

man man

man 2 <c-system function>ie. posix library

man 3 <c-library function>

search for page:

man -k <search term> or apropos <search term>

search for page content:

/<search term> to search inside “less”

man <page> | grep <search term> to pipe through grep

enable scrolling:

man <search term> | cat to be able to scroll

search for examples:

Debugging tools

GDB

Valgrind (finding memory leaks)

https://bytes.usc.edu/cs104/wiki/valgrind/

https://www.youtube.com/watch?v=DyqstSE470s

https://www.youtube.com/watch?v=8JEEYwdrexc

https://github.com/osue-tuwien/osue-tuwien.github.com/wiki/Valgrind

valgrind --leak-check=full --show-leak-kinds=all -s ./myProgram

useful flags:

--tool=memcheck→ is active by default

--track-origins=yes→ shows precise origins of errors with traceback

Strace (listening to kernel calls)

Visual Studio Code (config)