Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
3.8 KiB
Styleguide
This file is the source of truth for how vlibc code looks. .clang-format is
generated from / kept in sync with it.
Language
- C23 is the default standard; C2y (C29) is opt-in via
--enable-c29. - GCC only. Compiler extensions (
__attribute__, statement expressions,deferunder C2y) are permitted and encouraged where they improve clarity or performance.
Formatting
- 4-space indent, no tabs.
- 100-column limit.
- Allman braces: opening brace on its own line, for functions and blocks.
- Always use braces, even for single-statement blocks (avoids
goto fail-style bugs and matches.clang-tidy). - Pointer and qualifier attach to the name:
const char *s,int *p. - Spaces around binary operators; no space after unary operators.
The one exception to Allman braces is the C++ linkage guard: extern "C" {
keeps its opening brace attached (encoded as AfterExternBlock: false in
.clang-format), because that is the idiomatic form every C header uses.
int
foo(const char *s, size_t n)
{
if (n == 0)
{
return 0;
}
return (int)(s[0] == 'x');
}
Naming
- Functions and variables:
snake_case. - Types:
snake_case(struct tags); typedefs avoid the POSIX-reserved_tsuffix. - Macros and constants:
UPPER_SNAKE_CASE. - Public identifiers are prefixed
vlibc_to avoid collisions. - Identifiers beginning with
_(or__, or_[A-Z]) are reserved for the implementation and the C/POSIX standards — do not introduce new ones.
Include guards
Public headers use traditional include guards:
#ifndef VLIBC_H
#define VLIBC_H
...
#endif /* VLIBC_H */
#pragma once is a widely supported extension but is deliberately not used:
it relies on compiler-specific path canonicalization and can mis-deduplicate
headers reachable through symlinks or bind mounts. For a libc whose headers are
consumed in many toolchain configurations, explicit guards are the robust
default.
Compiler intent
Public declarations annotate intent so the compiler can optimize statically
linked binaries (see docs/overview.md):
__attribute__((const))— result depends only on arguments.__attribute__((pure))— no side effects; may read memory.__attribute__((always_inline)),__attribute__((leaf)),__attribute__((malloc)),__attribute__((access, ...))— as appropriate.
Every public function carries the tightest correct attribute.
Profile gating
Profile-gated code follows these formatting and naming conventions (the
semantic classification of functions into levels lives in
docs/compatibility.md, not here):
-
Public headers gate declarations with
#if VLIBC_LEVEL >= N. Prefer theVLIBC_LEVEL_GE(n)helper frominclude/vlibc/features.h; fall back to the raw comparison only when the level is a literal constant:#if VLIBC_LEVEL_GE(2) size_t strlcpy(char *dst, const char *src, size_t n); #endif -
Group implementation sources by level in
Makefile.amusing the per-level conditionalsif PROFILE_GE_2/if PROFILE_GE_3, mirroring the#if VLIBC_LEVEL >= Nrule in headers. -
Standard headers use
VLIBC_-prefixed include guards (VLIBC_STDDEF_H,VLIBC_STRING_H), never the_STDDEF_H-style reserved forms. A leading underscore is reserved for the implementation and the C/POSIX standards (see Naming); theVLIBC_prefix stays out of the reserved namespace while remaining unambiguous. -
Intent attributes respect the gating:
pure/constare only valid on side-effect-free functions. Never annotate a mutating function (memcpy,memmove,memset,strlcpy,strlcat) with either.
Error handling
- No empty blocks; no silent failure.
- Library functions return errors via return codes or
errno; they never terminate the caller's process.