aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2025-linuxdays/anon.c17
-rw-r--r--2025-linuxdays/bitfield.c17
-rw-r--r--2025-linuxdays/bits.c20
-rw-r--r--2025-linuxdays/cleanup.c16
-rw-r--r--2025-linuxdays/constructor.c15
-rw-r--r--2025-linuxdays/funcptr.c19
-rw-r--r--2025-linuxdays/generic.c13
-rw-r--r--2025-linuxdays/nonnull.c12
-rw-r--r--2025-linuxdays/overflow.c11
-rw-r--r--2025-linuxdays/pres.pdfbin0 -> 78378 bytes
-rw-r--r--2025-linuxdays/pres.typ494
-rw-r--r--2025-linuxdays/priv.c38
-rw-r--r--2025-linuxdays/static_assert.c9
-rw-r--r--2025-linuxdays/swrange.c14
-rw-r--r--2025-linuxdays/transunion.c14
-rw-r--r--2025-linuxdays/transunionf.c15
-rw-r--r--2025-linuxdays/warn-switch.c14
-rw-r--r--2025-linuxdays/weak.c11
-rw-r--r--2025-linuxdays/weakfun.c3
19 files changed, 752 insertions, 0 deletions
diff --git a/2025-linuxdays/anon.c b/2025-linuxdays/anon.c
new file mode 100644
index 0000000..392534b
--- /dev/null
+++ b/2025-linuxdays/anon.c
@@ -0,0 +1,17 @@
+#include <inttypes.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ struct point {
+ union {
+ struct {
+ uint32_t x, y;
+ };
+ uint64_t u64;
+ };
+ };
+
+ struct point a = {.x = 0x56, .y = 0x38};
+ printf("%.16" PRIx64 "\n", a.u64);
+ return 0;
+}
diff --git a/2025-linuxdays/bitfield.c b/2025-linuxdays/bitfield.c
new file mode 100644
index 0000000..a854158
--- /dev/null
+++ b/2025-linuxdays/bitfield.c
@@ -0,0 +1,17 @@
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ union pixel {
+ struct c {
+ unsigned r : 5;
+ unsigned g : 6;
+ unsigned b : 5;
+ } c;
+ uint16_t val;
+ };
+
+ union pixel p = {.c.r = 0x1b, .c.g = 0x4, .c.b = 0xa};
+ printf("%.4" PRIx16 " == %" PRIx16 "\n", p.val, 0x1b | 0x4 << 5 | 0xa << 11);
+}
diff --git a/2025-linuxdays/bits.c b/2025-linuxdays/bits.c
new file mode 100644
index 0000000..f16b232
--- /dev/null
+++ b/2025-linuxdays/bits.c
@@ -0,0 +1,20 @@
+#include <assert.h>
+#include <stdbit.h>
+
+int main(int argc, char *argv[]) {
+ assert(stdc_leading_zeros(0xffU) == 24);
+ assert(stdc_leading_ones(0xff000000U) == 8);
+ assert(stdc_trailing_zeros(0xff000000U) == 24);
+ assert(stdc_trailing_ones(0xffU) == 8);
+ assert(stdc_first_leading_zero(0xff000000U) == 9);
+ assert(stdc_first_leading_one(0xffU) == 25);
+ assert(stdc_first_trailing_zero(0xffU) == 9);
+ assert(stdc_first_trailing_one(0xff000000U) == 25);
+ assert(stdc_count_zeros(0xffU) == 24);
+ assert(stdc_count_ones(0xffU) == 8);
+ assert(stdc_has_single_bit(1U << 13));
+ assert(stdc_bit_width(0xf0U) == 8);
+ assert(stdc_bit_floor(0xf1U) == 0x80);
+ assert(stdc_bit_ceil(0xf1U) == 0x100);
+ return 0;
+}
diff --git a/2025-linuxdays/cleanup.c b/2025-linuxdays/cleanup.c
new file mode 100644
index 0000000..078114f
--- /dev/null
+++ b/2025-linuxdays/cleanup.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdbit.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void _free(char **ptr) {
+ printf("Freeing %p=%p\n", ptr, *ptr);
+ free(*ptr);
+}
+
+int main(int argc, char *argv[]) {
+ [[gnu::cleanup(_free)]] char *buf = malloc(18);
+ [[gnu::cleanup(_free)]] char *null = NULL;
+ printf("Pointers: %p=%p %p=%p\n", &buf, buf, &null, null);
+ return 0;
+}
diff --git a/2025-linuxdays/constructor.c b/2025-linuxdays/constructor.c
new file mode 100644
index 0000000..08e2b6c
--- /dev/null
+++ b/2025-linuxdays/constructor.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+[[gnu::constructor]]
+static void _our_constructor(void) {
+ printf("Constructor\n");
+}
+[[gnu::destructor]]
+static void _our_destructor(void) {
+ printf("Destructor\n");
+}
+
+int main(int argc, char *argv[]) {
+ printf("main\n");
+ return 0;
+}
diff --git a/2025-linuxdays/funcptr.c b/2025-linuxdays/funcptr.c
new file mode 100644
index 0000000..e4b3a83
--- /dev/null
+++ b/2025-linuxdays/funcptr.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+typedef void (*cb_t)(void *, int);
+typedef cb_t *scb_t;
+struct cb {
+ cb_t cb;
+ const char *str;
+};
+void cb(void *self, int v) {
+ struct cb *s = self;
+ printf("%s: %d\n", s->str, v);
+}
+#define callcb(CB, ...) (*(CB))(CB, __VA_ARGS__)
+
+int main(int argc, char *argv[]) {
+ struct cb c = {.cb = cb, .str = "Hello"};
+ scb_t sc = &c.cb;
+ callcb(sc, 42);
+}
diff --git a/2025-linuxdays/generic.c b/2025-linuxdays/generic.c
new file mode 100644
index 0000000..dcb9a78
--- /dev/null
+++ b/2025-linuxdays/generic.c
@@ -0,0 +1,13 @@
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#define traceval(X) \
+ fprintf(stderr, _Generic((X), char *: "%s\n", int: "%d\n", void *: "%p\n"), X)
+
+int main(int argc, char *argv[]) {
+ traceval("Hello");
+ traceval(42);
+ traceval(NULL);
+ return 0;
+}
diff --git a/2025-linuxdays/nonnull.c b/2025-linuxdays/nonnull.c
new file mode 100644
index 0000000..7e2c644
--- /dev/null
+++ b/2025-linuxdays/nonnull.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+[[gnu::nonnull]]
+void prnt(char *str) {
+ printf("%s\n", str);
+}
+
+int main(int argc, char *argv[]) {
+ prnt("Some text");
+ prnt(NULL);
+ return 0;
+}
diff --git a/2025-linuxdays/overflow.c b/2025-linuxdays/overflow.c
new file mode 100644
index 0000000..a21bf10
--- /dev/null
+++ b/2025-linuxdays/overflow.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include <stdckdint.h>
+#include <stdint.h>
+
+int main(int argc, char *argv[]) {
+ int8_t add, sub, mul;
+ assert(ckd_add(&add, 50, 85));
+ assert(ckd_sub(&sub, 10, 150));
+ assert(ckd_mul(&mul, 68, 2));
+ return 0;
+}
diff --git a/2025-linuxdays/pres.pdf b/2025-linuxdays/pres.pdf
new file mode 100644
index 0000000..c1f98c8
--- /dev/null
+++ b/2025-linuxdays/pres.pdf
Binary files differ
diff --git a/2025-linuxdays/pres.typ b/2025-linuxdays/pres.typ
new file mode 100644
index 0000000..f0c8730
--- /dev/null
+++ b/2025-linuxdays/pres.typ
@@ -0,0 +1,494 @@
+#import "@preview/polylux:0.4.0": *
+#import "@preview/metropolis-polylux:0.1.0" as metropolis
+
+#show: metropolis.setup
+#show: metropolis.setup.with(footer: [Pokročilé praktiky v C])
+
+#slide[
+ #set page(header: none, footer: none, margin: 3em)
+
+ #text(size: 1.3em)[*Pokročilé praktiky v C*]
+
+ LinuxDays 2025
+
+ #metropolis.divider
+
+ #set text(size: .8em, weight: "light")
+ Karel Kočí
+
+ 4.10.2025
+
+ https://git.cynerd.cz/presentations/tree/2025-linuxdays
+]
+
+#slide[
+= Svět C
+
+Standardy: C89, C95, C99, *C11*, C17, *C23*
+
+Kompilátory: *GCC*, *Clang*, MSVC, a další
+
+Standardní knihovny: *GLibC*, *Musl*, BSD, Nuttx, CRT
+
+\+ POSIX
+
+```c
+gcc -std=c23 ...
+clang -std=c23 ...
+```
+]
+
+#metropolis.new-section[Před C11\
+ Tohle už asi používáte]
+
+#slide[
+= Bitfield
+```c
+ union pixel {
+ struct c {
+ unsigned r : 5;
+ unsigned g : 6;
+ unsigned b : 5;
+ } c;
+ uint16_t val;
+ };
+ union pixel p = {.c.r = 0x1b, .c.g = 0x4, .c.b = 0xa};
+ printf("%.4" PRIx16 " == %" PRIx16 "\n",
+ p.val, 0x1b | 0x4 << 5 | 0xa << 11);
+```
+
+```
+$ gcc -std=c23 bitfield.c && ./a.out
+509b == 509b
+```
+]
+
+#slide[
+= Struktura s veřejnou částí / Rozhraní
+```c
+struct pub { void (*print_name)(struct pub *); };
+typedef struct pub *pub_t;
+#define pub_print_name(PUB) (PUB)->print_name(PUB)
+
+struct priv { struct pub pub; const char *name; };
+void pname_priv(struct pub *pub) {
+ struct priv *priv = (struct priv *)pub;
+ printf("%s", priv->name);
+}
+int main(int argc, char *argv[]) {
+ struct priv priv = {.pub = {pname_priv}, .name = "FOO"};
+ pub_t p = &priv.pub;
+ pub_print_name(p);
+ putchar('\n');
+```
+]
+
+#slide[
+= Struktura s veřejnou částí / Rozhraní
+```c
+struct wrap { struct pub *subpub; struct pub pub; };
+void pname_wrap(struct pub *pub) {
+ struct wrap *wrap = (void *)pub - offsetof(struct wrap, pub);
+ printf("Wrap: ");
+ wrap->subpub->print_name(wrap->subpub);
+}
+int main(int argc, char *argv[]) {
+ ...
+ struct wrap wrap = {.pub = {pname_wrap}, .subpub = &priv.pub};
+ wrap.pub.print_name(&wrap.pub);
+ putchar('\n');
+}
+```
+]
+
+#slide[
+= Double-pointer na funkci / Generická funkce
+```c
+typedef void (*cb_t)(void *, int);
+typedef cb_t *scb_t;
+struct cb { cb_t cb; const char *str; };
+void cb(void *self, int v) {
+ struct cb *s = self;
+ printf("%s: %d\n", s->str, v);
+}
+#define callcb(CB, ...) (*(CB))(CB, __VA_ARGS__)
+ struct cb c = {.cb = cb, .str = "Hello"};
+ scb_t sc = &c.cb;
+ callcb(sc, 42);
+```
+
+```
+$ gcc -std=c23 funcptr.c && ./a.out
+Hello: 42
+```
+]
+
+#metropolis.new-section["Novinky" v C]
+
+#slide[
+= Anonymní struct a union (*C11*)
+```c
+ struct point {
+ union {
+ struct {
+ uint32_t x, y;
+ };
+ uint64_t u64;
+ };
+ };
+
+ struct point a = {.x = 0x56, .y = 0x38};
+ printf("%.16" PRIx64 "\n", a.u64);
+```
+]
+
+#slide[
+= Static assert (*C11*)
+
+- *C11*: `_Static_assert`
+- *C23*: `static_assert`
+
+```c
+ static_assert(sizeof(intmax_t) >= 16,
+ "Platform must support 64bit integers")
+```
+
+```
+$ gcc -std=c23 static_assert.c
+static_assert.c:4:1: error: static assertion failed: "Platform must support 128bit integers"
+ 4 | static_assert(sizeof(intmax_t) >= 16, "Platform must support 128bit integers");
+ | ^~~~~~~~~~~~~
+```
+]
+
+#slide[
+= Atomic (*C11*)
+
+```c
+ #include <stdatomic.h>
+ _Atomic _Bool a; atomic_bool a;
+ _Atomic int val; atomic_int val;
+ _Atomic struct foo *foo;
+ _Bool aa = atomic_load(&a); aa = a;
+ atomic_store(&a, false); a = false;
+
+ #if (ATOMIC_BOOL_LOCK_FREE, 2)
+ // atomic_bool je vždy atomický bez zámku
+ #elif (ATOMIC_BOOL_LOCK_FREE, 1)
+ // atomic_bool někdy musí použít zámek
+ #else
+ // atomic_bool vždy použije zámek
+ #endif
+```
+]
+
+#slide[
+= Atomické operace (*C11*)
+
+```c
+ _Bool was = atomic_exchange(&a, false);
+ if (!atomic_compare_exchange_strong(&a, &was, true))
+ printf("Somebody changed it in the meantime\n");
+
+ int iwas = atomic_fetch_add(&val, 1);
+ iwas = atomic_fetch_sub(&val, 1);
+ iwas = atomic_fetch_or(&val, 0xf);
+ iwas = atomic_fetch_xor(&val, 0x10);
+ iwas = atomic_fetch_and(&val, 0xff);
+```
+]
+
+#slide[
+= Atomický příznak (*C11*)
+
+```c
+ atomic_flag event = ATOMIC_FLAG_INIT;
+ _Bool was = atomic_flag_test_and_set(&event);
+ atomic_flag_clear(&event);
+```
+]
+
+#slide[
+= Vlákna a další (*C11*)
+
+- `<threads.h>`
+- `thrd_t`, `mtx_t`, `cnd_t`
+- `thread_local` (`_Thread_local`) a `tss_t`
+]
+
+#slide[
+= Detekce přetečení a podtečení (*C23*)
+
+```c
+ int8_t add, sub, mul;
+ assert(ckd_add(&add, 50, 85));
+ assert(ckd_sub(&sub, 10, 150));
+ assert(ckd_mul(&mul, 68, 2));
+```
+
+Pozor: `true` = nevalidní výsledek
+]
+
+#slide[
+= Bitové operace (*C23*)
+
+```c
+ #include <stdbit.h>
+ assert(stdc_leading_zeros(0xffU) == 24);
+ assert(stdc_leading_ones(0xff000000U) == 8);
+ assert(stdc_trailing_zeros(0xff000000U) == 24);
+ assert(stdc_trailing_ones(0xffU) == 8);
+ assert(stdc_first_leading_zero(0xff000000U) == 9);
+ assert(stdc_first_leading_one(0xffU) == 25);
+ assert(stdc_first_trailing_zero(0xffU) == 9);
+ assert(stdc_first_trailing_one(0xff000000U) == 25);
+ assert(stdc_count_zeros(0xffU) == 24);
+ assert(stdc_count_ones(0xffU) == 8);
+ assert(stdc_bit_width(0xf0U) == 8);
+ assert(stdc_bit_floor(0xf1U) == 0x80);
+ assert(stdc_bit_ceil(0xf1U) == 0x100);
+```
+]
+
+#slide[
+= \_Generic (*C11*)
+```c
+#define traceval(X) \
+ fprintf(stderr, _Generic((X), \
+ char *: "%s\n", int: "%d\n", void *: "%p\n"), X)
+
+ traceval("Hello");
+ traceval(42);
+ traceval(NULL);
+```
+
+```
+$ gcc -std=c23 generic.c && ./a.out
+Hello
+42
+(nil)
+```
+
+Pozor: Všechny varianty musí být kompilovatelné.\
+Každá varianta generuje errory i warningy!
+]
+
+#slide[
+= Attributy (*C23*)
+
+Bylo ```c __attribute__(...)``` a nyní ```c [[...]]```.
+]
+
+#metropolis.new-section[Nestandardní C\
+ C podle kompilátoru]
+
+#slide[
+= Warning - switch
+
+```c
+int val = fgetc(stdin);
+switch (val) {
+ case ' ': printf("Secret space.... ");
+ default: printf("Got: %c\n", val);
+}
+```
+```
+$ gcc -Wimplicit-fallthrough -Wall -std=c23 warn-switch.c && ./a.out
+warn-switch.c: In function ‘main’:
+warn-switch.c:7:5: warning: this statement may fall through [-Wimplicit-fallthrough=]
+ 7 | printf("Secret space.. ");
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~
+warn-switch.c:8:3: note: here
+ 8 | default:
+ | ^~~~~~~
+```
+]
+
+#slide[
+= Warning - switch
+
+```c
+int val = fgetc(stdin);
+switch (val) {
+ case ' ':
+ printf("Secret space.... ");
+ [[gnu::fallthrough]];
+ default:
+ printf("Got: %c\n", val);
+}
+```
+]
+
+#slide[
+= Warningy
+
+- ```c [[gnu::fallthrough]]```
+- ```c [[gnu::nonstring]]```
+- ```c [[gnu::unused]]```
+]
+
+#slide[
+= nonnull
+```c
+[[gnu::nonnull]] // [[gnu::nonnull(1)]]
+void prnt(char *str) { printf("%s\n", str); }
+ prnt("Some text");
+ prnt(NULL);
+```
+
+```
+$ gcc -std=c23 nonnull.c && ./a.out
+nonnull.c: In function ‘main’:
+nonnull.c:10:3: warning: argument 1 null where non-null expected [-Wnonnull]
+ 10 | prnt(NULL);
+ | ^~~~
+nonnull.c:4:6: note: in a call to function ‘prnt’ declared ‘nonnull’
+ 4 | void prnt(char *str) {
+ | ^~~~
+Some text
+(null)
+```
+]
+
+#slide[
+= Další kontroly
+
+- ```c [[clang::counted_by]]```, ```c [[gnu::counted_by]]```
+- ```c [[gnu::malloc]]```
+- ```c [[gnu::alloc_size]]```
+- ```c [[gnu::fd_arg]]```, ```c [[gnu::fd_arg_read]]```, ```c [[gnu:fd_arg_write]]```
+- ```c [[gnu:: format]]```, ```c [[gnu:: format_arg]]]```
+
+https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
+https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
+https://clang.llvm.org/docs/AttributeReference.html
+]
+
+#slide[
+= Automatické uvolnění z heapy
+```c
+static void _free(char **ptr) {
+ printf("Freeing %p=%p\n", ptr, *ptr);
+ free(*ptr);
+}
+ [[gnu::cleanup(_free)]] char *buf = malloc(18);
+ [[gnu::cleanup(_free)]] char *null = NULL;
+ printf("Pointers: %p=%p %p=%p\n", &buf, buf, &null, null);
+```
+
+```
+$ gcc -std=c23 cleanup.c && ./a.out
+Pointers: 0x7ffffffdef68=0x4052a0 0x7ffffffdef70=(nil)
+Freeing 0x7ffffffdef70=(nil)
+Freeing 0x7ffffffdef68=0x4052a0
+```
+]
+
+#slide[
+= Weak
+```c
+[[gnu::weak]]
+void weakfun(void) {
+ printf("Weak function\n");
+}
+ weakfun();
+
+void weakfun(void) { printf("Standard function\n"); }
+```
+
+```
+$ gcc -std=c23 weak.c && ./a.out
+Weak function
+$ gcc -std=c23 weak.c weakfun.c && ./a.out
+Standard function
+```
+]
+
+#slide[
+= Transparent union
+```c
+union [[gnu::transparent_union]] un {
+ void *ptr;
+ intptr_t i;
+};
+void pasi(union un v) { printf("%p\n", v.ptr); }
+ pasi((intptr_t)0x42);
+ pasi((void *)&pasi);
+```
+
+```
+$ gcc -std=c23 transunion.c && ./a.out
+0x42
+0x401150
+```
+]
+
+#slide[
+= Transparent union callback
+```c
+union [[gnu::transparent_union]] un {
+ char *ptr;
+ intptr_t i;
+};
+void call(void (*cb)(union un)) { cb("FOO"); }
+void cb(char *str) { printf("%s\n", str); }
+ call(cb);
+```
+
+```
+$ gcc -std=c23 transunionf.c && ./a.out
+FOO
+```
+]
+
+#slide[
+= Constructor a Desctructor
+```c
+[[gnu::constructor]]
+static void _our_constructor(void) { printf("Constructor\n"); }
+[[gnu::destructor]]
+static void _our_destructor(void) { printf("Destructor\n"); }
+int main(int argc, char *argv[]) {
+ printf("main\n");
+}
+```
+
+```
+$ gcc -std=c23 constructor.c && ./a.out
+Constructor
+main
+Destructor
+```
+]
+
+#slide[
+= Switch range (GCC, Clang, ...)
+```c
+ int val = getchar();
+ switch (val) {
+ case '0' ... '9':
+ printf("Number\n");
+ break;
+ default:
+ printf("Not a number\n");
+ break;
+ }
+```
+]
+
+#slide[
+ #show: metropolis.focus
+ Děkuji za pozornost
+
+ Karel Kočí
+
+ #metropolis.divider
+
+ #text(size: 0.7em)[
+ https://git.cynerd.cz
+
+ https://gitlab.com/cynerd
+
+ https://git.cynerd.cz/presentations/tree/2025-linuxdays
+ ]
+]
diff --git a/2025-linuxdays/priv.c b/2025-linuxdays/priv.c
new file mode 100644
index 0000000..ed3ad1a
--- /dev/null
+++ b/2025-linuxdays/priv.c
@@ -0,0 +1,38 @@
+#include <stddef.h>
+#include <stdio.h>
+
+struct pub {
+ void (*print_name)(struct pub *);
+};
+typedef struct pub *pub_t;
+#define pub_print_name(PUB) (PUB)->print_name(PUB)
+
+struct priv {
+ struct pub pub;
+ const char *name;
+};
+void pname_priv(struct pub *pub) {
+ struct priv *priv = (struct priv *)pub;
+ printf("%s", priv->name);
+}
+
+struct wrap {
+ struct pub *subpub;
+ struct pub pub;
+};
+void pname_wrap(struct pub *pub) {
+ struct wrap *wrap = (void *)pub - offsetof(struct wrap, pub);
+ printf("Wrap: ");
+ wrap->subpub->print_name(wrap->subpub);
+}
+
+int main(int argc, char *argv[]) {
+ struct priv priv = {.pub = {pname_priv}, .name = "FOO"};
+ pub_t p = &priv.pub;
+ pub_print_name(p);
+ putchar('\n');
+
+ struct wrap wrap = {.pub = {pname_wrap}, .subpub = &priv.pub};
+ wrap.pub.print_name(&wrap.pub);
+ putchar('\n');
+}
diff --git a/2025-linuxdays/static_assert.c b/2025-linuxdays/static_assert.c
new file mode 100644
index 0000000..23ffbc8
--- /dev/null
+++ b/2025-linuxdays/static_assert.c
@@ -0,0 +1,9 @@
+#include <stdint.h>
+#include <stdio.h>
+
+static_assert(sizeof(intmax_t) >= 16, "Platform must support 128bit integers");
+
+int main(int argc, char *argv[]) {
+ printf("In the main\n");
+ return 0;
+}
diff --git a/2025-linuxdays/swrange.c b/2025-linuxdays/swrange.c
new file mode 100644
index 0000000..1889ba4
--- /dev/null
+++ b/2025-linuxdays/swrange.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ int val = getchar();
+ switch (val) {
+ case '0' ... '9':
+ printf("Number\n");
+ break;
+ default:
+ printf("Not a number\n");
+ break;
+ }
+ return 0;
+}
diff --git a/2025-linuxdays/transunion.c b/2025-linuxdays/transunion.c
new file mode 100644
index 0000000..cde6059
--- /dev/null
+++ b/2025-linuxdays/transunion.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <stdio.h>
+
+union [[gnu::transparent_union]] un {
+ void *ptr;
+ intptr_t i;
+};
+
+void pasi(union un v) { printf("%p\n", v.ptr); }
+
+int main(int argc, char *argv[]) {
+ pasi((intptr_t)0x42);
+ pasi((void *)&pasi);
+}
diff --git a/2025-linuxdays/transunionf.c b/2025-linuxdays/transunionf.c
new file mode 100644
index 0000000..e210194
--- /dev/null
+++ b/2025-linuxdays/transunionf.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+#include <stdio.h>
+
+union [[gnu::transparent_union]] un {
+ char *ptr;
+ intptr_t i;
+};
+
+void call(void (*cb)(union un)) { cb("FOO"); }
+void cb(char *str) { printf("%s\n", str); }
+
+int main(int argc, char *argv[]) {
+ call(cb);
+ return 0;
+}
diff --git a/2025-linuxdays/warn-switch.c b/2025-linuxdays/warn-switch.c
new file mode 100644
index 0000000..0de8859
--- /dev/null
+++ b/2025-linuxdays/warn-switch.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ int val = getchar();
+ switch (val) {
+ case ' ':
+ printf("Secret space.. ");
+ [[gnu::fallthrough]];
+ default:
+ printf("Got: '%c'\n", val);
+ break;
+ }
+ return 0;
+}
diff --git a/2025-linuxdays/weak.c b/2025-linuxdays/weak.c
new file mode 100644
index 0000000..4dea695
--- /dev/null
+++ b/2025-linuxdays/weak.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+[[gnu::weak]]
+void weakfun(void) {
+ printf("Weak function\n");
+}
+
+int main(int argc, char *argv[]) {
+ weakfun();
+ return 0;
+}
diff --git a/2025-linuxdays/weakfun.c b/2025-linuxdays/weakfun.c
new file mode 100644
index 0000000..edde6dd
--- /dev/null
+++ b/2025-linuxdays/weakfun.c
@@ -0,0 +1,3 @@
+#include <stdio.h>
+
+void weakfun(void) { printf("Standard function\n"); }