Test pseudo-namespaces in C

In C you can create pseudo-namespaces by abusing structs of function
pointers, making function calls look like `module.func(x)` instead of
`func(x)`.

A lot of people online spout that this creates overhead, but this should
show that clang>=15.0.7 will still inline such function calls. GCC 11.3.1
is unable  to inline the function, but will still call the function
directly.
This commit is contained in:
olemorud
2023-06-06 11:32:12 +02:00
commit 0c33a58da0
7 changed files with 122 additions and 0 deletions

20
CMakeLists.txt Normal file
View File

@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.13)
project(Namespaces)
add_executable(main
module.c
main.c)
target_compile_options(main
PRIVATE
-Werror -Wall -Wextra -O3 -g -std=c2x -flto)
target_link_options(main
PRIVATE
-flto -Wl,-O2)
target_compile_definitions(main
PRIVATE
-DNAMESPACES)

29
Makefile Normal file
View File

@@ -0,0 +1,29 @@
CC ?= clang
# compiler specific flags
CFLAGS.gcc :=
CFLAGS.clang :=
# general flags
CFLAGS := \
-Wall -Wextra -Werror -Wpedantic \
-O3 -g -flto \
-std=c2x \
${CFLAGS.${CC}} \
-DNAMESPACES \
LDFLAGS := \
-flto \
-Wl,-O3
dump.asm : test
gdb $< -batch -ex 'disassemble main' > $@
(gdb $< -batch -ex 'disassemble succ' >> $@) || true
test : main.o module.o
$(CC) $(CFLAGS) -o $@ $^
%.o : %.c
$(CC) $(CFLAGS) -o $@ -c $^

21
build.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
requirements=("cmake" "gdb")
for cmd in $requirements; do
if ! command -v gdb; then
echo "gdb not found"
exit 1
fi
done
mkdir -p build
(cd build
rm * -rf
CC=clang cmake ..
make -j2
)
gdb ./build/main -batch -ex 'disassemble main' > dump.asm
gdb ./build/main -batch -ex 'disassemble succ' 1>> dump.asm 2>/dev/null || true

10
dump.asm Normal file
View File

@@ -0,0 +1,10 @@
Dump of assembler code for function main:
0x0000000000401130 <+0>: push %rax
0x0000000000401131 <+1>: mov $0x402010,%edi
0x0000000000401136 <+6>: mov $0x6,%esi
0x000000000040113b <+11>: xor %eax,%eax
0x000000000040113d <+13>: call 0x401030 <printf@plt>
0x0000000000401142 <+18>: xor %eax,%eax
0x0000000000401144 <+20>: pop %rcx
0x0000000000401145 <+21>: ret
End of assembler dump.

22
main.c Normal file
View File

@@ -0,0 +1,22 @@
#include <stdio.h>
#include "module.h"
int main()
{
int x = 4;
#ifdef NAMESPACES
#pragma message "namespaces enabled"
x = module.succ(x);
x = module.succ(x);
#else
x = succ(x);
x = succ(x);
#endif
printf("%d\n", x);
return 0;
}

12
module.c Normal file
View File

@@ -0,0 +1,12 @@
#include "module.h"
inline int succ(int x)
{
return x+1;
}
struct exports module = {
.succ = succ,
};

8
module.h Normal file
View File

@@ -0,0 +1,8 @@
int succ(int x);
struct exports {
int (*succ)(int);
};
extern struct exports module;