30

I'm looking for the most recent versions of modern C compilers which were/are targeting DOS 8086, also running on DOS 8086 (16-bit). I'm mostly interested in production-ready C compilers, rather than hobby projects (possibly many bugs yet to be discovered).

By modern I mean:

  • support for ANSI C (C89) source files
  • support for generating small model and large model DOS .exe programs

See in my answer what I've found to work.

I'm aware of the following C compilers, but they are not answers to my question, because they have some required features missing:

  • LSI C-86 3.30c released on 1993-08-23: It doesn't support the large memory model.

  • DeSmet C 3.1h (1988) and DeSmet C 3.1N (1992): It seems to support ANSI C and the large memory model. (Compile hello.c using the small model: c88 hello; bind hello. Compile hello.c using the large model: c88 hello b; bbind hello) But it doesn't support the unsigned long type. Also I wasn't able to define a function which takes variable number of arguments (va_list args; doesn't compile). Also compilation breaks in weird ways, e.g. foo->field = 42; doesn't compile (but (*foo).field = 42; does), but then in the next line it compiles. I've given up on this compiler, it has too many bugs.

  • PCC 1.2d: It has the same engine as DeSmet C 2.51. It doesn't support the large memory model.

  • HI-TECH Software Pacific C 7.51 released on 1996-01-20 (and re-released with a less restrictive license on 2000-05-10): (1) the compiler is generating some useless overflow warnings for numbers between -40 and 40, so there may be many code generation bugs, probably not worth the effort; (2) the compiler is running out of memory for my tools which Borland Turbo C++ 1.01, Borland C++ 2.0 and Microsoft C 6.00a can compile easily. I've given up on it.

  • Manx Software Systems Aztec C86 5.2a released on 1992-11-17. It isn't able to compile my tools, the assembler fails with out-of-memory error. Borland C++, Microsoft C and Zortech C++ are all able to compile the program successfully. Also with the -ansi flag it displays some weird error messages (all other modern and all the mentioned old C compilers succeed), I'm not sure how easy it is to work around the errors. It does support the small and large models.

  • SubC 2014-05-25 released on 2014-05-25. It doesn't support many C language features, e.g. typedef. The port running on DOS 8086 is experimental.

I'm aware of the following C compilers, but they are not answers to my question, because they don't run on DOS 8086:

  • OpenWatcom: I've successfully compiled C code targeting DOS 8086 with the most recent build 2022-11-22 on DOSBox with 5 MiB of memory. Arguably OpenWatcom is the most modern C/C++ compiler still targeting DOS 8086. However, the DOS port of the compiler itself runs in 32-bit protected mode, and thus needs a 386 processor. I'm not using the DOS port though, the native ports to my laptop are faster, and they produce the same DOS program.

  • GCC: It doesn't support 8086 as a target.

  • DJGPP: It doesn't support 8086 as a target.

  • gcc-ia16. Supports multiple memory models (e.g. -mcmodel=small and -mcmodel=large) for DOS 8086.

  • Clang: It doesn't support 8086 as a target.

  • Microsoft Visual C++: It doesn't support 8086 as a target. The last Microsoft compiler with DOS 8086 as a target was Microsoft C++ 8.00c.

  • Borland C++ Builder: It doesn't support 8086 as a target.

  • TinyCC (TCC): It doesn't support 8086 as a target.

  • Digital Mars C/C++ 8.57 released on 2022-05-14: The compiler .exe files are for Win32, they don't run on DOS 8086. However, it supports DOS 8086 as a target (at least for compiling C code to an OMF .obj file), with multiple memory models (e.g. dmc -ms and dmc -ml).

  • Smaller C 1.0.1 released on 2021-09-14: Even the DOS real mode compiler tools (e.g. bind/smlrc.exe) need a 386 CPU.

  • Symantec C/C++: It supports DOS 8086 as a target (at least for compiling C code to an OMF .obj file), with multiple memory models (e.g. sc -ms and sc -ml). This is the successor of Zortech C++, and the compiler executable programs probably run in protected mode, thus they need a 386 CPU. Maybe version 6.0 still contains DOS 8086 programs, I have to try. In version 6.1 there is the sc -b ... command-line flag, but the corresponding scc.exe (C compiler for DOS 8086) and scpp.exe (C++ compiler for DOS 8086) are not provided, probably they were never released. The protected mode programs sccx and scppx.exe run in protected mode, and need a 386 CPU (they work in DOSBox with 2 MiB of memory). Release history:

    • Symantec C++ Professional 6.0 was released in 1993-09.
    • Symantec C++ Professional 6.1 was released in 1993-12.
    • Symantec C++ 7.0 for Windows was released in 1995-07.
    • Symantec C++ 7.2 for Windows 95, Windows NT 3.5, Windows 3.1 and DOS was released in 1995-10.
    • Symantec C++ 7.50 was released in 1997.

Is there any C compiler I've missed? Maybe there is a much more recent (than 1992) minimalistic C compiler.

pts
  • 1,859
  • 9
  • 17
  • 1
    What purpose do you need it for? – Thorbjørn Ravn Andersen Nov 23 '22 at 23:56
  • 8
    @ThorbjørnRavnAndersen: I'm writing some tools for DOS 8086 in C89 (currently compiling them with OpenWatcom targeting DOS 8086), and I was wondering if it was possible to compile them on DOS 8086. If yes, I may want to compare the behavior of different compilers and C libraries, and port my Watcom-specific optimizations. – pts Nov 24 '22 at 00:06
  • 5
    Makes sense. There is nothing wrong with cross compiling though. – Thorbjørn Ravn Andersen Nov 24 '22 at 06:10
  • 1
    I'm surprised to see TCC on the list at all; it can't even target 16-bit mode x86, unless I'm missing something in the docs (https://bellard.org/tcc/tcc-doc.html#linker). (But it's open source, so you could compile it to run on DOS and make Linux ELF or Windows PE executables.) – Peter Cordes Nov 25 '22 at 04:52
  • 2
    If you’re going to look at DeSmet C, you might as well use the last release, 3.1N. Also, Zortech C++ 3.0r2 works on an 8086. Finally, re Pacific C, the 2000 release date is misleading: 7.51 was released as shareware in 1996, requalified as freeware in 1998 without change, and re-released without the shareware nags in 2000. The compiler itself is unchanged AFAIK. – Stephen Kitt Nov 25 '22 at 08:22
  • @StephenKitt: Indeed, if I run Zortech C++ 3.x (tried both 3.0r1 and 3.1) as ztc -b ..., then it works on DOS 8086. Without the -b flag, it needs a 386 CPU on DOS. I'm updating my answer. – pts Nov 25 '22 at 10:44
  • 1
    Would you be interested in alternative languages other than C - for instance PL/M86. It isn't as modern but code generation is good and unlike most C compilers, the in/out functions translate directly to assembler instead of being subroutine calls like in most C compilers. – cup Dec 10 '22 at 08:31
  • 1
    For many purposes, code which mostly uses the "small" memory model, but has a few machine-language routines to access "far" routines or memory, can be more efficient than code which uses the "large" memory model. Would such a design be worth considering? – supercat Jan 18 '23 at 18:07
  • @cup: In this question I'm interested in C compilers only, and I predict that I will write all my DOS programs in NASM assembly, Watcom C or Borland C. However, it is worth asking about PL/M compilers targeting DOS 8086 and PL/M compilers running on DOS 8086, feel free to do so. – pts Jan 18 '23 at 20:15
  • @supercat: Yes, I'm using such a trick in one of my programs, which I compile with Watcom C. However, I don't have the time to rewrite most of the existing C code written by someone else, requiring the large model. Also, I use support for the large model in a C compiler as an indicator for high quality: give me a high quality (correct, fast, optimizing, using little memory) C89 compiler targeting DOS which doesn't support the large model -- I haven't yet found one. – pts Jan 18 '23 at 20:23
  • I don’t see the Manx Aztec C mentioned. Been using it for nearly 40 years! :) – Miker Mar 28 '23 at 00:37
  • 1
    I think Microsoft QuickC ran on 8086 machines as well. I do recall that it offered the ability to generate 8086 and 80286 code, but nothing higher than that. Was decent enough, but I do recall that I had issues with the math library at the time beyond a few decimal places precision (circa 1992/1993). – bjb Mar 28 '23 at 16:14
  • @Miker: As I wrote in my earlier comment, Aztec C 5.2a for DOS isn't able to compile my program, the assembler fails with out-of-memory error. Borland C++, Microsoft C and Zortech C++ are all able to compile the program successfully. Also with the -ansi flag it displays some weird error messages (all other modern and all the mentioned old C compilers succeed), I'm not sure how easy it is to work around the errors. It does support the small and large models, and it can compile a hello-world program successfully. – pts Mar 28 '23 at 19:41
  • @bjb: Thank you for mentioning QuickC, I've added it to my answer. – pts Apr 04 '23 at 10:15
  • 1
    A thought: Have you considered making the C compiler you need your target project? – Thorbjørn Ravn Andersen Apr 06 '23 at 10:50
  • @ThorbjørnRavnAndersen: I was considering compiling the most recent OpenWatcom C compiler with itself, creating wcc.exe for DOS 8086. I think the compiler code size is too large, there won't be enough of the 635 KiB of memory remaining for the code to be compiled. Earlier versions were smaller. – pts Apr 06 '23 at 14:29
  • That is most likely why the switch happened so fast. Compiler writers really liked the large 386 memory space – Thorbjørn Ravn Andersen Apr 06 '23 at 16:26
  • Nevertheless, it's possible (but hard) to write a full and correct ANSI C89 compiler running on and targeting DOS 8086, as a 300 KiB .exe program. This question is a survey on the state of the art. – pts Apr 06 '23 at 16:36
  • @pts: It's not particularly difficult to design an efficient 16-bit C89 compiler for tasks that don't require accessing more than 64K of data. It's not really possible to design a 16-bit compiler that can efficiently access more than that without relying upon language extensions, because in many cases performing tasks efficiently requires copying data that might be "anywhere" into a buffer that's known to be within the main 64K data segment, acting upon it with pointers that compiler knows will always point within the primary 64K segment, and then writing data back to main memory. – supercat May 26 '23 at 14:26
  • @pts: I wish C89 had recognized the potential existence of __near and __far qualifiers, with the semantics that implementations need not do anything with them, but systems may have an implementation-defined limit on the amount of storage that's qualified near, and a farmalloc function which returns a far-qualified pointer might have access to storage which is only accessible via far-qualified pointer (and farmemcpy, farmemmove, etc.), Portable code could selectively define macros like near3, near2, etc.. that could be defined as __near or nothing based upon... – supercat May 26 '23 at 14:31
  • 1
    ...the amount of near storage available. So on any platform one could start defining them all as near, see if things fit, then undefine one of them, see if things fit, etc. Even when targeting something like the 68000 or ARM, the efficiency of code that uses many file-scope variables could be improved by having a register dedicated to holding the start of "near" storage, and using register-displacement addressing to access such things (classic Apple Macintosh used A5 for that purpose). – supercat May 26 '23 at 14:35
  • @supercat: My survey results (right in this question and its answer) indicate that many C compilers have weird bugs and arbitrary memory limits (e.g. one runs out of memory in the assembler), so writing an ANSI C89 compiler and getting it right is quite hard. – pts May 26 '23 at 18:38
  • 1
    @pts: Many "bugs" involve corner cases that few people cared about, but where the authors of the Standard felt they had to specify something, and in many cases mandated an inferior behavior. For example, Tuirbo C "incorrectly" processes an expression like (0x1E-x) as a useful expression that subtracts x from thirty, while gcc "correctly" requires that a programmer wanting that meaning must insert whitespace after the E. On the flip side, gcc and clang generate nonsensical code in corner cases where the Standard is unambiguous, but behaving as described by the Standard would block... – supercat May 26 '23 at 18:56
  • ...an optimization that would relatively offer much value in non-contrived situations. Note that C89 and every version since is written in such a way that such bugs will almost never render an otherwise-conforming compiler non-conforming, so the ease or difficulty of making a conforming implementation depends upon how one would seek to define quality. – supercat May 26 '23 at 18:56

3 Answers3

20

The most recently-released C compiler I’m aware of for 16-bit DOS (host and target) is HI-TECH Software’s Pacific C, version 7.51, released on 1996-01-20. The IDE, PPD, requires a 286, but PACC, the command-line compiler driver, runs on an 8086.

There might have been a later release of a Digital Mars (formerly Zortech) C compiler hosted on 16-bit DOS, but I’m not familiar with the DOS-hosted history of that compiler after Zortech C++ 3.0r2 (1991-08-02), which is the last version that run on an 8086. Zortech C++ became Symantec C++, which was only available hosted on Windows, and then the Digital Mars Development System, which is also only available hosted on Windows.

Stephen Kitt
  • 121,835
  • 17
  • 505
  • 462
  • 3
    More DOS compilers listed here: https://www.thefreecountry.com/compilers/cpp.shtml – John Dallman Nov 24 '22 at 13:52
  • 1
    FYI I'm trying to compile my tools with Pacific C on DOS, but (1) the compiler is generating some useless overflow warnings for numbers between -40 and 40, so there may be many code generation bugs, probably not worth the effort; (2) the compiler is running out of memory for my tools which Borland Turbo C++ 1.01, Borland C++ 2.0 and Microsoft C 6.00a can compile easily. – pts Nov 24 '22 at 15:10
  • Can you cite your source mentioning that Pacific C 7.51 was released on 1996-01-26? I can't find it online. The self-extracting LHA archive pacific.exe has 2000-05-10 as most recent member file mtime. – pts Nov 24 '22 at 15:52
  • 1
    @pts see https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/devel/c/pacific/shareware-free/, the contents of the archive there are dated 1996-01-20 (not 26, that was a typo). The archives themselves are dated 1998-07-13 which is when the shareware Pacific C was made free (see https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/devel/c/pacific/shareware-free/readme.txt). – Stephen Kitt Nov 24 '22 at 16:17
  • @JohnDallman: Thank you for the link. I've added all relevant compilers there back to my question. Some of them look promising, I'll update the question as soon as I have taken a closer look. – pts Nov 25 '22 at 03:37
  • 1
    @pts: Is bcc useful for this? It's been updated as recently as 1995 per FreeBSD version numbering (https://www.freshports.org/devel/bcc), and is open source (GPLv2) so presumably compilable for 8086. But it's not modern, apparently limited to K&R C, not ANSI / C89 with prototypes. Part of https://github.com/lkundrak/dev86 (I didn't check git history for more recent BCC updates). dev86 was used by ELKS (a subset of Linux on 8086). Example codegen: How to compile with Bruce's C Compiler to get asm for 8086 – Peter Cordes Nov 25 '22 at 11:29
  • 2
    @PeterCordes bcc only supports the small memory model. It has had more recent updates, the latest release with bcc changes was 0.16.20 in October 2013. – Stephen Kitt Nov 25 '22 at 11:42
  • 1
    Oh right, I missed the part of the question stating that requirement. Should probably be on the list in the question of compilers ruled out for various reasons. – Peter Cordes Nov 25 '22 at 12:23
  • @StephenKitt: How hard would it be to use with bcc a few machine-code functions to read or write bytes or words given a segment/offset pair, or copy multiple bytes or words between blocks at two arbitrary seg/offset pairs? For many tasks, such an approach would allow more efficient code than using the large memory model. – supercat Jan 18 '23 at 18:05
  • @supercat I suppose that really depends on what you consider hard ;-). It’s certainly possible to do so, and it can be done without changes to any library as long as the caller always ensures that data passed to and from library functions is in the main segment. Anything beyond that would of course require changes to the library. – Stephen Kitt Jan 19 '23 at 11:23
14

There's also the Zortech C compiler from Walter Bright at his Digital Mars site. It supports 16 bits (DOS, Windows) and 32 bits (DOS with extender, Windows and OS/2). Walter Bright works now mostly on his new language D but still supports his C and C++ compiler when something important happens.

https://www.digitalmars.com/download/freecompiler.html

Patrick Schlüter
  • 4,120
  • 1
  • 15
  • 22
11

I can confirm that the following C compilers work. I've also indicated the latest version of each which still runs on DOS 8086.

  • Borland Turbo C++ 1.01 released on 1991-02-27. The next version, 3.00 has tcc.exe which needs a 386 or newer processor.
  • Borland C++ 2.0 released on 1991-04-23. The next version, 3.00 has bcc.exe which needs a 386 or newer processor.
  • Microsoft C 6.00a released on 1990-09-12. The next version, 7.0 has cl.exe which needs a 386 or newer processor. C++ support was added in 7.0.
  • Microsoft QuickC 2.51 released on 1990-04-06. It has a command-line compiler (qcl.exe) and linker (qlink.exe). The C language it accepts (_MSC_VER = 600) is simular to Microsoft C 5.1 or 6.00a (_MSC_VER = 600). Newer versions of Microsoft QuickC needed Microsoft Windows to run, and they didn't include a command-line compiler.
  • Zortech C++ 3.1 released on 1992-12-07. The compiler supports both C and C++, depending on the source file extension. To run it on DOS 8086, invoke it as ztc -b .... Without the -b flag it needs a 386 CPU, and it runs in protected mode. It seems to work for my test tool programs with minor modifications, like the compilers above.
  • Watcom C9.0 released in 1992, containing wcc.exe. I wasn't able to obtain and try this. All internet sources I've found contain Watcom C9.0/386, which contains the wcc386.exe compiler, which targets the 386 CPU. The next version, Watcom C9.01/386 (released on 1992-05-28) has only the wcc386.exe, which runs on DOS 8086 and targets the 386 CPU. The next version, 9.5 has wcc.exe which needs a 386 or newer processor. Please note that I wasn't able to get a copy of wcc.exe (which targets the 8086 in 16-bit mode) in Watcom C 9.0, but only the wcc386.exe in Watcom C 9.01 (which targets the 386 in 32-bit mode, and is a DOS 8086 .exe program). See the EDM/2 history page for Watcom C for more details about Watcom C versions before 9.5.

I've also tried compilers suggested in other answers, but either they don't run on DOS 8086, or they have some features lacking or serious bugs which prevent me from using them.

pts
  • 1,859
  • 9
  • 17
  • 4
    I'm a fan of Turbo C 2.x. I used it on a 4.77MHz 8088 until I got my 80386, and while its performance wasn't as good as Turbo Pascal it was still adequate (much better than Turbo C++). I think the version I downloaded from the Borland Museum was almost the same as the one I used back in the day, except that on the Museum version, printf("%0.1f", 99.96 would correctly output 100.0 while my version from the 1980s would output 00.0. – supercat Jan 18 '23 at 22:22
  • 1
    Unfortunately the Borland Museum site seems no longer to exist. community.borland.com/museum/ – hptsb Mar 19 '24 at 12:52