0%

Redefinition type in the same scope for C23

C23有一項特性

Structure, union and enumeration types may be defined more than once in the same scope with the same contents and the same tag; if such types are defined with the same contents and the same tag in different scopes, the types are compatible.

以下的程式碼在C23是合法的

1
2
3
4
5
6
7
struct A {
    int a;
};

struct A {
    int a;
};

而在C23之前會被歸類成 redefinition of 'struct A'
有了這個,在C語言寫類Generic 會比較方便
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#define Result_t(T, E) struct Result_##T##_##E { bool is_ok; union { T value; E error; }; }

#define Ok(T, E) (struct Result_##T##_##E){ .is_ok = true, .value = (T) _OK_IMPL
#define _OK_IMPL(...) __VA_ARGS__ }

#define Err(T, E) (struct Result_##T##_##E){ .is_ok = false, .error = (E) _ERR_IMPL
#define _ERR_IMPL(...) __VA_ARGS__ }

typedef const char *ErrorMessage_t;

Result_t(int, ErrorMessage_t) my_func(int i)
{
if (i == 42) return Ok(int, ErrorMessage_t)(100);
else return Err(int, ErrorMessage_t)("Cannot do the thing");
}

int main()
{
Result_t(int, ErrorMessage_t) x = my_func(42);

if (x.is_ok) {
printf("%d\n", x.value);
} else {
printf("%s\n", x.error);
}
}

目前只有GCC 14.1支持

不過事情總不可能永遠事事順利,總是有會碰到支援舊的Compiler這種事
這邊看到不錯的解決方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#if __STDC_VERSION__ >= 202311L
#define Neat_SString(cap) \
struct SString_##cap \
{ \
unsigned int len; \
unsigned char chars[ cap + 1 ]; /* + 1 for the nul */ \
}

#define NEAT_DECL_SSTRING(cap)
#else
#define Neat_SString(cap) \
struct SString_##cap

#define NEAT_DECL_SSTRING(cap) \
struct SString_##cap \
{ \
unsigned int len; \
unsigned char chars[ cap + 1 ]; /* + 1 for the nul */ \
}
#endif

Reference