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
https://courses.cs.washington.edu/courses/cse333/19sp/sections/02/gdb-valgrind cheatsheet.pdf
https://www.youtube.com/watch?v=MTkDTjdDP3c&list=PLvv0ScY6vfd-GGT-aUH31X2yXgBSYXo6t&index=3
https://github.com/osue-tuwien/osue-tuwien.github.com/wiki/gdb
$ gdb -tui ./<program name>
(gdb) b <line to break>
(gdb) run <arguments for program>
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)