diff options
| -rw-r--r-- | 2025-linuxdays/anon.c | 17 | ||||
| -rw-r--r-- | 2025-linuxdays/bitfield.c | 17 | ||||
| -rw-r--r-- | 2025-linuxdays/bits.c | 20 | ||||
| -rw-r--r-- | 2025-linuxdays/cleanup.c | 16 | ||||
| -rw-r--r-- | 2025-linuxdays/constructor.c | 15 | ||||
| -rw-r--r-- | 2025-linuxdays/funcptr.c | 19 | ||||
| -rw-r--r-- | 2025-linuxdays/generic.c | 13 | ||||
| -rw-r--r-- | 2025-linuxdays/nonnull.c | 12 | ||||
| -rw-r--r-- | 2025-linuxdays/overflow.c | 11 | ||||
| -rw-r--r-- | 2025-linuxdays/pres.pdf | bin | 0 -> 78378 bytes | |||
| -rw-r--r-- | 2025-linuxdays/pres.typ | 494 | ||||
| -rw-r--r-- | 2025-linuxdays/priv.c | 38 | ||||
| -rw-r--r-- | 2025-linuxdays/static_assert.c | 9 | ||||
| -rw-r--r-- | 2025-linuxdays/swrange.c | 14 | ||||
| -rw-r--r-- | 2025-linuxdays/transunion.c | 14 | ||||
| -rw-r--r-- | 2025-linuxdays/transunionf.c | 15 | ||||
| -rw-r--r-- | 2025-linuxdays/warn-switch.c | 14 | ||||
| -rw-r--r-- | 2025-linuxdays/weak.c | 11 | ||||
| -rw-r--r-- | 2025-linuxdays/weakfun.c | 3 |
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 Binary files differnew file mode 100644 index 0000000..c1f98c8 --- /dev/null +++ b/2025-linuxdays/pres.pdf 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"); } |
