writing-c
Skill4 starsChanged 7 months agoMITView on GitHub
Coding style and guidance when writing C code. Use whenever C code is being written, read or updated.
We split this skill into the rules it gives an agent
23 rules. About 0 are common, 10 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 24
If the project is a module, a cmhg directory will exist with a file describing the module definition and entry points.
- Very specific: line 25
If the project name is not otherwise given, the environment variable $ROBUILD_PROJECT contains its name.
- Very specific: line 28
Place separate functionality in separate files.
- Distinctive: line 44
All variable declarations must appear at the top of their block, before any statements.
- Very specific: line 45
Use int32_t, uint32_t and friends as appropriate.
- Very specific: line 46
When representing on-disk or in-memory RISC OS layout fields with a fixed binary size, prefer explicit fixed-width types such as int32_t …
- Very specific: line 47
If you get errors from the compiler like Serious error: <command> expected but found '<type>', this probably means that there is a variable …
- Distinctive: line 50
Do not leave trailing spaces, even on blank lines.
- Very specific: line 52
Use enum if you need to enumerate a set of values like state values.
- Very specific: line 53
Use #define for values like bit-fields and constant strings.
- Distinctive: line 72
Add comments to describe intent.
- Distinctive: line 99
Treat the 64-bit build as a stricter compiler pass, even when the 32-bit Norcroft build is happy.
- Very specific: line 100
Do not define a private static helper with the same name as a shared helper already declared in a header.
- Very specific: line 102
Keep 32-bit-only SWI or ABI dependencies behind narrow helper functions so they can be #ifdef __riscos64 guarded cleanly.
- Distinctive: line 106
When porting code that talks to the graphics or pointer system, separate it into:
- Distinctive: line 123
When part of the implementation drops below the normal graphics interfaces and touches screen memory directly, isolate that path behind …
- Distinctive: line 131
When porting BBC BASIC code that uses fixed-offset records and ad hoc blocks:
- Distinctive: line 139
When tests are skipped because of OS version or environment restrictions, count and report the skipped cases explicitly.
- Distinctive: line 159
Static/non-static declaration mismatch: Check whether a source file has redefined a helper which is already declared in a shared header or …
- Very specific: line 160
Undefined symbols at link time: Check if o.modhead (the CMHG object) or your assembly objects (e.g., o.veneer) are missing from the OBJS …
- Distinctive: line 161
Implicit declaration warnings in 64-bit builds: Treat these as real porting work, especially for SWI wrappers and kernel helper entry …
- Very specific: line 168
Use riscos-libsearch to find exported headers, libraries, functions and defines:
- Very specific: line 175
If /riscos-built/Export has changed and lookup results look stale, run riscos-libsearch --index to rebuild the user-built index.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Guidance for writing C code.
Project Structure
- Source file conventions:
- C source files live in a directory called
c, and do not have an extension. - C header files live in a directory called
h, and do not have an extension. - For example, a C file for writing files might be called
c/file_writer, and its header would be calledh/file_writer. - Within the source files, the convention is still to use the extension, for example,
#include "file_writer.h". - The filenames must NEVER be in the form
c/filename.corh/filename.h.
- C source files live in a directory called
- Makefile files have names that start with
Makefileand end with,fe1.- Makefile include files can be found in the directory
$AMUFILES.
- Makefile include files can be found in the directory
- Built absolutes:
aif32/<name>,ffa(32-bit absolute) oraif64/<name>,ffa(64-bit absolute) - Built modules:
rm32/<name>,ffa(32-bit module) orrm64/<name>,ffa(64-bit module) - BBC BASIC files are named with a suffix of
,fd1. They do not need line numbers. - The version number of the project is in
VersionNum, a C include file which describes values. - If the project is a module, a
cmhgdirectory will exist with a file describing the module definition and entry points. - If the project name is not otherwise given, the environment variable
$ROBUILD_PROJECTcontains its name. - RISC OS application names should normally be capitalised and should generally avoid hyphens.
- For example, prefer
WimpClicksoverwimp-clicksfor the built application and package name.
- For example, prefer
- Place separate functionality in separate files. For example, module interfaces should be in
c/module, and hardware interface would be inc/hardware.
In the filesystem:
Wrong:
c/name.ch/name.h
Correct:
c/nameh/name
C Coding style
- Code conforms largely to C89.
- All variable declarations must appear at the top of their block, before any statements. Create new blocks to ensure that variables are scoped in their use. Do not declare variables inline with code.
- Use
int32_t,uint32_tand friends as appropriate.int64_tis not available for 32-bit, but is available in the 64-bit compiler. - When representing on-disk or in-memory RISC OS layout fields with a fixed binary size, prefer explicit fixed-width types such as
int32_trather thanint, so the layout remains correct in 64-bit builds. - If you get errors from the compiler like
Serious error: <command> expected but found '<type>', this probably means that there is a variable declaration in the middle of the function. C89 requires that variable declarations be at the start of the block.
- Braces go at the start of lines (not the ends).
- Indentation is 4 characters.
- Do not leave trailing spaces, even on blank lines.
- Magic numbers and strings (bare numbers and strings in the code) should be avoided.
- Use
enumif you need to enumerate a set of values like state values. - Use
#definefor values like bit-fields and constant strings.
- Use
No Threading
RISC OS is single-threaded. Do not use threading or assume re-entrancy.
Includes
- You may use includes
stdint.handstdbool.hif needed. - Interfacing with the OS and calling SWIs will usually need
kernel.handswis.h. - Include
stdlib.hfor NULL when needed.
Commenting
- Retain comments where they remain correct.
- Add comments to describe intent.
- Functions should include a prologue comment to describe the function's purpose and arguments, in a similar style to the rest of the project.
- Both C and H files should contain a prologue comment to describe the file's purpose, and its relationship to others in the project, if necessary.
File prologues:
/*******************************************************************
* File: filename
* Purpose: Description
* Author: AUTHOR
******************************************************************/Function prologues:
/*******************************************************************
Function: function_name
Description: Description of function
Parameters: var = value
Returns: none
******************************************************************/64-bit build notes
- Treat the 64-bit build as a stricter compiler pass, even when the 32-bit Norcroft build is happy.
- Do not define a private
statichelper with the same name as a shared helper already declared in a header. The 64-bit toolchain will reject this immediately. - Code that calls low-level kernel helpers should be checked for 64-bit visibility and availability. If a helper is not available for
__riscos64, either provide a real 64-bit implementation or return an explicit unsupported/error result rather than relying on implicit declarations. - Keep 32-bit-only SWI or ABI dependencies behind narrow helper functions so they can be
#ifdef __riscos64guarded cleanly.
Porting graphics-dependent code
When porting code that talks to the graphics or pointer system, separate it into:
- pure algorithmic control flow
- state queries
- side-effect backends
This makes it possible to implement and test the orchestration logic before the real plotting or output backend exists. For example, tiled sprite plotting can be implemented as:
- local tile placement logic
- a support hook to read graphics bounds and eig factors
- repeated calls into the lower-level sprite plotting reason
That keeps partial implementations honest and avoids hard-coding fake graphics behaviour into otherwise reusable logic.
When part of the implementation drops below the normal graphics interfaces and touches screen memory directly, isolate that path behind dedicated helpers. That makes it easier to keep cursor removal, mode checks, and 32-bit/64-bit differences local to the framebuffer code instead of leaking through the general rendering logic.
Porting record-based BASIC code
When porting BBC BASIC code that uses fixed-offset records and ad hoc blocks:
- Convert the record layouts into explicit C structures with descriptive member names before rewriting the higher-level logic.
- Pull narrow behavioural rules into pure helpers where practical, especially for geometry adjustment, selection arithmetic, and message-block construction.
- For Wimp or clipboard protocols, separate block construction from message sending so the protocol details can be regression-tested without a live desktop session.
Self-test reporting
When tests are skipped because of OS version or environment restrictions, count and report the skipped cases explicitly. Do not silently reduce the apparent coverage of the test run.
Compilation and linking errors
- "Serious error:
<command>expected": This is almost always a C89 violation where a variable was declared after a statement. Move all declarations to the top of the{ }block, or wrap the logic in a new{ ... }block:
void my_function(void)
{
int i = 0;
do_something();
{
int j = 5; // Valid in C89 because it's at the top of this sub-block
do_more(j);
}
}- Static/non-static declaration mismatch: Check whether a source file has redefined a helper which is already declared in a shared header or implemented elsewhere.
- Undefined symbols at link time: Check if
o.modhead(the CMHG object) or your assembly objects (e.g.,o.veneer) are missing from theOBJSvariable in your makefile. - Implicit declaration warnings in 64-bit builds: Treat these as real porting work, especially for SWI wrappers and kernel helper entry points.
Standard C files
- The C includes for RISC OS can be found in the directories:
/riscos-built/Export/C/and/riscos-built/Export/Lib- searched first./riscos-resources/Export/C/and/riscos-resources/Export/Lib- searched second.
- Use
riscos-libsearchto find exported headers, libraries, functions and defines:riscos-libsearch ScreenSave- find a function or define by name.riscos-libsearch Sprite.h- find matching headers and their host filenames.riscos-libsearch --symbols riscos/Sprite.h- list symbols from a header.riscos-libsearch --lib RISC_OSLib- show a library's headers, objects and symbols.riscos-libsearch --lib-list- list known libraries.
riscos-libsearchreads the baked system index from/riscos-resources/Export/Lib/libraries.dband, when present, the user-built index from/riscos-built/Export/libraries.db. Built results take priority over system results for the same include path.- If
/riscos-built/Exporthas changed and lookup results look stale, runriscos-libsearch --indexto rebuild the user-built index. - RISC OS interface values and constants can be found in the following includes (include name
riscos/NAME.his held in fileriscos/h/NAME):riscos/CMOS.h- NVRAM valuesriscos/DynArea.h- Dynamic area constantsriscos/EnvNumbers.h- Program environment registration valuesriscos/Events.h- Event numbersriscos/FileTypes.h- RISC OS file type numbersriscos/Heap.h-OS_Heapconstantsriscos/Messages.h- Wimp message numbersriscos/ModeVariables.h-OS_ReadModeVariableandOS_ReadVduVariablesvaluesriscos/ModHand.h- RISC OS module area constantsriscos/NewErrors.h- Error numbers and standard stringsriscos/OSPlatformFeatures.h- Platform informationriscos/OSReadSysInfo.h- OS informationriscos/OSScreenMode.h- Screen mode selection and informationriscos/Oswords.h-OS_Wordconstantsriscos/Pointer.h-OS_Pointerconstantsriscos/Services.h- Service numbers.riscos/Sprite.h-OS_SpriteOpconstantsriscos/UpCall.h-OS_UpCallconstantsriscos/Vectors.h- Vector numbers
In this repository47 other files it gives its agents.
- allocating-resourcesSkill
- ci-testingSkill
- creating-pull-requestsSkill
- designing-modulesSkill
- porting-to-riscos-cSkill
- reading-assemblySkill
- riscos-commandsSkill
- riscos-desktop-fileractionSkill
- riscos-filer-likeSkill
- riscos-filesystemSkill
- riscos-graphics-convertersSkill
- riscos-network-dcistatisticsSkill
- riscos-network-resolverSkill
- riscos-outputSkill
- riscos-reSkill
- riscos-styleSkill
- riscos-throwbackSkill
- riscos-urls-fetchingSkill
- riscos-urls-launchingSkill
- riscos-wimp-appSkill
- riscos-wimpSkill
- riscos-wimp-templatesSkill
- updating-robe-skillsSkill
- using-bbcbasicSkill
- using-cmhgSkill
- using-ghSkill
- using-gitSkill
- using-libasmSkill
- using-libgcontextSkill
- using-liboslibSkill
- using-libriscoslibSkill
- using-libtoolboxSkill
- using-makefilesSkill
- using-perlSkill
- using-stronghelpSkill
- using-toolbox-imagefilegadgetSkill
- using-tooltesterSkill
- writing-assemblySkill
- writing-assembly-testsSkill
- writing-cmodulesSkill
- writing-cplusplusSkill
- writing-fortranSkill
- writing-oslib-defsSkill
- writing-pascalSkill
- writing-prminxmlSkill
- writing-pymodulesSkill
- writing-pyromaniac-integration-testsSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

