c – Coding skill for AI agents
Language-specific super-code guidelines for c.
Install the c skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/c-ce87d.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /c – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/c-ce87d.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $c – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/c-ce87d.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /c – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/c-ce87d.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /c – then describe the task you want done.
SKILL.md content
C: Idiomatic Efficiency Reference
Apply only within the requested scope and current project conventions. Preserve behavior, ownership, error handling, accessibility and security; examples are independent fragments, not equivalent rewrites in every context. Verify language/library versions and run relevant checks. Required tests and user-facing progress/results take precedence over brevity rules. Do not install dependencies or delete files merely to follow these examples.
When to Use
- Use this skill when the task matches this description: Language-specific super-code guidelines for c.
Table of Contents
1. [Memory Management](#memory)
2. [Pointers & Arrays](#pointers)
3. [Error Handling](#errors)
4. [Strings](#strings)
5. [Structs & Enums](#structs)
6. [Preprocessor & Headers](#preprocessor)
7. [Anti-patterns specific to C](#antipatterns)
---
1. Memory Management {#memory}
// ❌ malloc without checking return value
char *buf = malloc(size);
strcpy(buf, src);
// ✅
char *buf = malloc(size);
if (!buf) return -ENOMEM;
memcpy(buf, src, size);// ❌ Casting malloc result (unnecessary in C, hides missing #include)
int *p = (int *)malloc(n * sizeof(int));
// ✅
if (n > SIZE_MAX / sizeof(int)) return -ENOMEM;
int *p = malloc(n * sizeof *p);// ❌ free without nulling (dangling pointer risk in long-lived scope)
free(ptr);
// ... later code might use ptr
// ✅
free(ptr);
ptr = NULL;// ❌ Forgetting to free on early-return paths
char *a = malloc(100);
char *b = malloc(200);
if (!b) return -1; // leaks a
// ✅ — single cleanup label
char *a = NULL, *b = NULL;
a = malloc(100);
if (!a) goto cleanup;
b = malloc(200);
if (!b) goto cleanup;
// ... use a, b ...
cleanup:
free(b);
free(a);**Use sizeof *ptr instead of sizeof(Type) — it stays correct when the type changes.**
---
2. Pointers & Arrays {#pointers}
// ❌ Manual array size tracking
void process(int *arr, int len) { ... }
process(data, 10);
// ✅ — pass size alongside pointer, or use a struct
typedef struct { int *data; size_t len; } IntSlice;// ❌ Pointer arithmetic where array indexing is clearer
*(arr + i) = value;
// ✅
arr[i] = value;// ❌ VLA in production code (stack overflow risk, optional in C11+)
int arr[n];
// ✅
if (n > SIZE_MAX / sizeof(int)) return -ENOMEM;
int *arr = malloc(n * sizeof *arr);
if (!arr) return -ENOMEM;
// ... use arr ...
free(arr);---
3. Error Handling {#errors}
// ❌ Using magic numbers for error returns
if (do_thing() == -1) { ... }
// ✅ — define or use named error codes
#include <errno.h>
if (do_thing() < 0) {
int saved_errno = errno; // only when do_thing documents setting errno
perror("do_thing");
return saved_errno;
}// ❌ Deeply nested error checks
int r1 = step1();
if (r1 == 0) {
int r2 = step2();
if (r2 == 0) {
int r3 = step3();
// ...
}
}
// ✅ — early return / goto cleanup
if (step1() < 0) goto fail;
if (step2() < 0) goto fail;
if (step3() < 0) goto fail;
return 0;
fail:
cleanup();
return -1;goto cleanup is idiomatic C for resource teardown — don't avoid it out of principle.
---
4. Strings {#strings}
// ❌ strcpy without bounds checking
strcpy(dest, src);
// ✅
// Only when dest is an actual nonempty array, not a pointer.
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
// or better: snprintf(dest, sizeof(dest), "%s", src);// ❌ strcmp misuse
if (str == "hello") { ... } // compares pointers, not content
// ✅
if (strcmp(str, "hello") == 0) { ... }// ❌ Building strings with repeated strcat (O(n²))
char result[1024] = "";
for (int i = 0; i < n; i++) {
strcat(result, items[i]);
}
// ✅ — track write position
char result[1024];
size_t pos = 0;
result[0] = '\0';
for (int i = 0; i < n; i++) {
int written = snprintf(result + pos, sizeof(result) - pos, "%s", items[i]);
if (written < 0 || (size_t)written >= sizeof(result) - pos) return -1;
pos += (size_t)written;
}Prefer snprintf over sprintf — always.
---
5. Structs & Enums {#structs}
// ❌ Bare struct requiring `struct` keyword everywhere
struct point { int x, y; };
struct point p = {1, 2};
// ✅
typedef struct { int x, y; } Point;
Point p = {1, 2};// ❌ Uninitialized struct
Point p;
use(p.x); // UB
// ✅
Point p = {0};// ❌ Magic integer constants
if (state == 3) { ... }
// ✅
typedef enum { STATE_IDLE, STATE_RUNNING, STATE_DONE } State;
if (state == STATE_DONE) { ... }---
6. Preprocessor & Headers {#preprocessor}
// ❌ Macro where inline function works (no type safety, double eval)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
MAX(x++, y) // x incremented twice if x > y
// ✅
static inline int max_int(int a, int b) { return a > b ? a : b; }// ❌ No include guard
// my_header.h
struct Foo { int x; };
// ✅
#ifndef MY_HEADER_H
#define MY_HEADER_H
struct Foo { int x; };
#endif
// or: #pragma once (widely supported, not standard)Keep macros for conditional compilation and constants. Use static inline for logic.
---
7. Anti-patterns specific to C {#antipatterns}
| Anti-pattern | Preferred |
|---|---|
| sprintf | snprintf with buffer size |
| gets | fgets (gets is removed in C11) |
| Casting malloc result | let implicit void* conversion work |
| sizeof(Type) in malloc | sizeof *ptr |
| VLA for large/runtime arrays | heap allocation |
| void* callbacks without context param | pass void *ctx alongside function pointer |
| Global mutable state | pass state through struct pointers |
| assert for runtime error handling | proper error return codes |
| Missing const on read-only pointer params | const char *str |
| Mixing signed/unsigned in comparisons | use consistent types, cast explicitly |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.
Related skills
- c-pro – Review and implement C systems code with explicit memory ownership, pointer bounds…
- c4-architecture-c4-architecture – Generate comprehensive C4 architecture documentation for an existing repository/codebase…
- python-configuration – Python configuration management via environment variables and typed settings. Use when…
- opencode – Delegate coding to OpenCode CLI (features, PR review).
- c4-code – Expert C4 Code-level documentation specialist. Analyzes code directories to create…
- c4-component – Expert C4 Component-level documentation specialist. Synthesizes C4 Code-level…
- python-design-patterns – Python design patterns including KISS, Separation of Concerns, Single Responsibility…
- grill-with-docs – Docs-anchored grilling session — challenges a plan against the project's existing…