Writing Portable C Code with SAS/C¶
Vol 1 Ch.13 addresses the question every AmigaOS developer eventually asks: how do I write code that can move to a different compiler, OS, or architecture? The chapter surveys the portability pitfalls specific to SAS/C 6.58 and AmigaOS, and the constructs that travel well. Source: Vol 1 Ch.13, pp. 199–213.
The portability layers¶
Three concentric circles, from broadest to narrowest:
+------------------------------------------------+
| Standard C (K&R, C89, C99) | ← portable everywhere
+------------------------------------------------+
| SAS/C extensions ( __saveds, #pragma, ... ) | ← portable across Amiga
+------------------------------------------------+
| AmigaOS specifics ( dos.library, Intuition ) | ← portable across 68k Amiga only
+------------------------------------------------+
The portability goal determines which layer the code lives in:
- Cross-platform (Amiga, Linux, Mac): standard C + minimal platform-specific shims
- Cross-Amiga (68k AmigaOS, AmigaOS 4, MorphOS, AROS): SAS/C extensions OK, AmigaOS specifics must be wrapped
- Single-target (a specific AmigaOS version): direct API calls OK
Standard C vs SAS/C¶
Things that work on any C89/C99 compiler:
- All of standard C: control flow, structs, pointers, arrays, functions
<stdio.h>,<stdlib.h>,<string.h>,<math.h>,<time.h>enum,union,typedefconst,volatile
Things that don't:
| SAS/C construct | Why not portable |
|---|---|
__saveds |
Compiler-specific keyword |
__interrupt |
Compiler-specific keyword |
__regargs / __stdargs |
Compiler-specific calling convention |
__asm / #asm / #endasm |
Inline assembly is compiler-specific |
#pragma libcall |
SAS-specific pragma |
#pragma amicall |
SAS-specific (Aztec compatibility) |
#pragma msg |
SAS-specific diagnostic control |
BPTR, BSTR |
AmigaOS BCPL types |
ZERO, NULL (as BPTR) |
ZERO is AmigaOS-specific |
Portability wrapping patterns¶
Header shims¶
Create a single header that defines the portability layer:
/* portability.h — included by all source files */
#if defined(__SASC)
# include <proto/exec.h>
# include <proto/dos.h>
/* SAS/C specifics OK here */
#elif defined(__GNUC__)
# include <exec/types.h>
/* GCC specifics here */
#endif
/* Common typedefs */
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
/* Compiler-portable inlining */
#if defined(__SASC)
# define INLINE __inline
#elif defined(__GNUC__)
# define INLINE static inline
#else
# define INLINE static
#endif
AmigaOS function wrapping¶
Wrap AmigaOS-specific code in adapter functions, keep the rest portable:
/* portable.c */
#include "portability.h"
int read_file(const char *path, void *buf, int len)
{
#ifdef AMIGA
BPTR fh = Open((STRPTR)path, MODE_OLDFILE);
if (!fh) return -1;
LONG got = Read(fh, buf, len);
Close(fh);
return (int)got;
#else
FILE *f = fopen(path, "rb");
if (!f) return -1;
size_t got = fread(buf, 1, len, f);
fclose(f);
return (int)got;
#endif
}
The rest of the program uses read_file() and never sees Open/Read/fopen/fread.
Conditional compilation discipline¶
Put platform-specific code in a single port_*.c file, not scattered through the codebase:
project/
├── portability.h
├── port_amiga.c # AmigaOS implementation
├── port_linux.c # POSIX implementation
├── port_macos.c # macOS implementation
└── ... rest of code, all using portability.h
The build system picks the right port_*.c based on TARGET.
Porting from SAS/C to GCC¶
If you have SAS/C code and want to move to GCC (e.g., for cross-compilation to AmigaOS 4 or MorphOS), the main work is:
- Replace
__savedswith__attribute__((saveds))orstatic __attribute__((saveds))(the attribute is non-standard but supported by GCC for AmigaOS targets). - Replace
__interruptwith__attribute__((interrupt)). - Replace
#pragma libcall FooBase 1 123withLONG Foo(...);plus a manual jump-table offset, or use the NDKproto/headers that already declare them. - Replace
__regargswith__attribute__((regparm(3))). - Replace
#pragma msgwith__attribute__((warning("...")))or#pragma GCC warning. - Replace
BPTRwithAPTRif not actually a BCPL pointer. - Replace inline assembly with GCC inline assembly (different syntax).
- Update
smakefile→Makefile.
A typical porting effort: a few days for a small program (under 5000 lines), a few weeks for a large one.
Porting from GCC to SAS/C¶
The reverse direction is harder because GCC supports more extensions and a more recent C standard. Things to watch for:
- C99/C11 features not in SAS/C 6.58:
//comments (SAS does support them), designated initializers (supported), compound literals (not supported),inline(use__inline),restrict(no equivalent), variable-length arrays (no equivalent),<stdint.h>(no exact equivalent — defineuint32_tetc. manually). - GCC inline assembly syntax is different — rewrite as
.sfiles. __attribute__((packed))— SAS/C has no equivalent; use__attribute__if GCC, manual packing otherwise.
Porting the build system¶
smake and make are 80% similar. The main porting steps:
- Tabs.
smakerequires tabs;makeaccepts spaces but is more portable with tabs. - Shell commands.
delete(Amiga) →rm(POSIX). - Path separators.
/on AmigaOS since 2.0, but older code uses:. Standardize on/. - Assigns.
C:,INCLUDE:,LIBS:are Amiga-specific. Replace with absolute paths in a cross-platform Makefile. - Path wildcards. Amiga's
#?and?don't match*and?in Unix shells. Usewildcard(Make 3.81+) or list files explicitly.
The portability test¶
A practical rule: can you grep for the compiler-specific bits?
grep -E '__saveds|__interrupt|__regargs|#pragma libcall|BPTR' src/*.c
Any hits are portability issues. Either remove them, wrap them, or document why they are necessary.
What SAS/C gives you that the standard doesn't¶
Some SAS/C features have a portability cost but are still worth using on Amiga-only projects:
__saveds— required for correct callback behavior. No portable equivalent; the__attribute__form is GCC-specific.#pragma libcall— drastically cleaner than manual offset declarations. Use it.__savedsdata segment setup — fastest way to do base-relative addressing. Use it.- CodeProbe debugger — best AmigaOS-aware debugger of its era.
See Also¶
- SAS/C Compiler Reference
- SAS/C Extensions to C
- Coding Standards
- PowerPC and Future-OS Compatibility Rules
Sources: SAS Institute Inc., "SAS/C Development System User's Guide, Volume 1" Ch.13, Version 6.50 (1993), pp. 199–213.
Raw: raw/sasc/sasc-portable-c-extract.md
Updated: 2026-10-02