Compiling and Running (with gcc
)
A C program is written within a hello.c
with code below.
The main
method is the entrypoint of the program,
alongside sample ((constructor))
and ((destructor))
.
#include <stdio.h>
__attribute__((constructor)) void init() {
puts("pre hello world");
}
__attribute__((destructor)) void finish() {
puts("post hello world");
}
int main() {
puts("hello world");
return 0;
}
The program can be compiled into binary hello
and ran.
Further flags are often used to modulate the compilation step,
see the provided reference table.
gcc ./hello.c -o hello
./hello
Headers and Includes
Header files need to be included in C to declare symbols
(function and type definitions, constants, macros)
shared across multiple source files.
Including tells the compiler about the symbols prior to use,
allowing proper linkage, preventing undefined reference errors
during compilation.
Comes in 2 syntaxes, using the brackets or the quotes.
#include <stdio.h>
Brackets are used to include a pre-existing system header file,
that are specified in the POSIX standard.
The pre-processor uses the known system header location.
#include "path/to/file.h"
Quotes are used to to include a user-defined header file,
by specifying a path relative to the C source file.
Binairies and Compiling in Docker Containers
After compiling a C program on the host machine,
attempting to run it inside a docker container will likely fail.
This is due to the differences of libc
per distribution.
To fix this issue, one option is to bypass the problem by copying
the libc into the binary with gcc -static
;
another is to compile within the container:
FROM alpine:3.21
COPY ./hello.c .
RUN apk add build-base && gcc hello.c -o hello
ENTRYPOINT ["./hello"]