Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Language-specific super-code guidelines for c.
.claude/skills/lingxling-c/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 21% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 43% | 0% |
| case-14 | ✓→✓ | = Same ✓ | 159% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 93% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 179% | 0% |
c// ❌ malloc without checking return value char *buf = malloc(size); strcpy(buf, src); // ✅ char *buf = malloc(size); if (!buf) return -ENOMEM; memcpy(buf, src, size);
c// ❌ Casting malloc result (unnecessary in C, hides missing #include) int *p = (int *)malloc(n * sizeof(int)); // ✅ int *p = malloc(n * sizeof *p);
c// ❌ free without nulling (dangling pointer risk in long-lived scope) free(ptr); // ... later code might use ptr // ✅ free(ptr); ptr = NULL;
c// ❌ 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.
c// ❌ 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;
c// ❌ Pointer arithmetic where array indexing is clearer *(arr + i) = value; // ✅ arr[i] = value;
c// ❌ VLA in production code (stack overflow risk, optional in C11+) int arr[n]; // ✅ int *arr = malloc(n * sizeof *arr); if (!arr) return -ENOMEM; // ... use arr ... free(arr);
c// ❌ Using magic numbers for error returns if (do_thing() == -1) { ... } // ✅ — define or use named error codes #include <errno.h> if (do_thing() < 0) { perror("do_thing"); return errno; }
c// ❌ 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.
c// ❌ strcpy without bounds checking strcpy(dest, src); // ✅ strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0'; // or better: snprintf(dest, sizeof(dest), "%s", src);
c// ❌ strcmp misuse if (str == "hello") { ... } // compares pointers, not content // ✅ if (strcmp(str, "hello") == 0) { ... }
c// ❌ 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]; int pos = 0; for (int i = 0; i < n && pos < (int)sizeof(result); i++) { pos += snprintf(result + pos, sizeof(result) - pos, "%s", items[i]); }
Prefer snprintf over sprintf — always.
c// ❌ 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};
c// ❌ Uninitialized struct Point p; use(p.x); // UB // ✅ Point p = {0};
c// ❌ Magic integer constants if (state == 3) { ... } // ✅ typedef enum { STATE_IDLE, STATE_RUNNING, STATE_DONE } State; if (state == STATE_DONE) { ... }
c// ❌ 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; }
c// ❌ 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.
| 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 |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-14 | pass→pass | 5,714 | 4,306 | -25% | 1 | 1 | 0% | 896 | 2,319 | +159% | 0 | 0 | — |
case-01 | fail→pass | 21,422 | 17,111 | -20% | 1 | 1 | 0% | 3,537 | 4,296 | +21% | 0 | 0 | — |
case-02 | pass→pass | 9,246 | 7,782 | -16% | 1 | 1 | 0% | 1,646 | 3,185 | +93% | 0 | 0 | — |
case-03 | pass→pass | 7,014 | 4,075 | -42% | 1 | 1 | 0% | 890 | 2,487 | +179% | 0 | 0 | — |
case-04 | pass→pass | 15,817 | 10,101 | -36% | 1 | 1 | 0% | 2,286 | 3,216 | +41% | 0 | 0 | — |
case-05 | pass→pass | 15,838 | 7,410 | -53% | 1 | 1 | 0% | 3,084 | 3,132 | +2% | 0 | 0 | — |
case-06 | pass→pass | 18,168 | 13,275 | -27% | 1 | 1 | 0% | 3,428 | 4,291 | +25% | 0 | 0 | — |
case-07 | pass→pass | 7,444 | 14,010 | +88% | 1 | 1 | 0% | 635 | 2,339 | +268% | 0 | 0 | — |
case-08 | pass→pass | 11,356 | 9,105 | -20% | 1 | 1 | 0% | 1,962 | 3,029 | +54% | 0 | 0 | — |
case-09 | fail→fail | 11,443 | 13,299 | +16% | 1 | 1 | 0% | 2,343 | 4,479 | +91% | 0 | 0 | — |
case-10 | pass→pass | 10,726 | 11,375 | +6% | 1 | 1 | 0% | 1,958 | 3,516 | +80% | 0 | 0 | — |
case-11 | fail→pass | 15,771 | 8,866 | -44% | 1 | 1 | 0% | 2,361 | 3,386 | +43% | 0 | 0 | — |
case-12 | pass→pass | 5,994 | 4,282 | -29% | 1 | 1 | 0% | 887 | 2,387 | +169% | 0 | 0 | — |
case-13 | fail→fail | 18,444 | 19,720 | +7% | 1 | 1 | 0% | 3,476 | 4,918 | +41% | 0 | 0 | — |
case-15 | pass→pass | 12,788 | 4,009 | -69% | 1 | 1 | 0% | 1,926 | 2,204 | +14% | 0 | 0 | — |
case-16 | pass→pass | 10,361 | 5,091 | -51% | 1 | 1 | 0% | 1,490 | 2,435 | +63% | 0 | 0 | — |
case-17 | pass→pass | 12,868 | 6,421 | -50% | 1 | 1 | 0% | 2,437 | 2,654 | +9% | 0 | 0 | — |
case-18 | pass→pass | 9,094 | 6,985 | -23% | 1 | 1 | 0% | 1,403 | 2,995 | +113% | 0 | 0 | — |
case-19 | pass→pass | 13,064 | 3,651 | -72% | 1 | 1 | 0% | 2,101 | 2,308 | +10% | 0 | 0 | — |
case-20 | fail→fail | 20,278 | 28,044 | +38% | 1 | 1 | 0% | 3,231 | 6,021 | +86% | 0 | 0 | — |
case-21 | pass→pass | 11,875 | 13,736 | +16% | 1 | 1 | 0% | 2,121 | 4,245 | +100% | 0 | 0 | — |
case-22 | pass→pass | 21,056 | 14,129 | -33% | 1 | 1 | 0% | 3,132 | 4,253 | +36% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.