{"id":8051,"date":"2024-10-15T03:00:00","date_gmt":"2024-10-15T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=8051"},"modified":"2024-10-13T11:56:50","modified_gmt":"2024-10-13T15:56:50","slug":"programming-across-platforms","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=8051","title":{"rendered":"Programming across platforms"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"8051\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>The C programming language remains an extremely popular language due to its relatively simple syntax that allows you to write all kinds of programs. And because the C language is portable across so many systems, you can find a C compiler pretty much everywhere, to run your code on anything.<\/p>\n\n\n\n<p>But that portability can itself be a challenge, because while you can find a compiler for any system, that doesn\u2019t mean that they all work exactly the same. For example, C programs on Linux typically use <strong>curses<\/strong> to create text-mode programs that run on the terminal. But another platform might not use the <em>terminal<\/em> concept; notably, the DOS operating system used <em>direct access<\/em> to the video hardware to operate at the <em>console<\/em> using the <strong>conio<\/strong> library.<\/p>\n\n\n\n<p>If you\u2019re writing a C program that should operate on multiple systems, you can use the C <em>preprocessor<\/em> to provide a mechanism that recognizes what system you\u2019re compiling for, and insert the appropriate code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"preprocessor-directives\">Preprocessor directives<\/h2>\n\n\n\n<p>The preprocessor is part of the standard C compilation process, but you may not really think about it. For example, the line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;<\/code><\/pre>\n\n\n\n<p>\u2026 at the start of any program is an example of a preprocessor <em>directive<\/em> to include the <code>stdio.h<\/code> header file at that point in the code.<\/p>\n\n\n\n<p>The preprocessor operates this way on lines that start with <code>#<\/code> like this. And the preprocessor has other directives or command actions that it can take, including the <code>#define<\/code> action. In C programming, the <code>#define<\/code> allows you to define a macro that <em>never changes its value<\/em> and that you can reference later, such as the value of pi with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define PI 3.141<\/code><\/pre>\n\n\n\n<p>But the definition can be used in other ways too, including identifying the system at compile-time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"defining-the-system\">Defining the system<\/h2>\n\n\n\n<p>The C preprocessor creates a definition that identifies the platform you\u2019re compiling for. Let\u2019s say you\u2019re on Linux and compiling a program for Linux; your C compiler will automatically define a macro that identifies the system as Linux.<\/p>\n\n\n\n<p>It\u2019s very common for this definition to be written in all lowercase, and begin and end with two underscores, like <code>__linux__<\/code> to identify the system as Linux. At the same time, because Linux is a Unix-like operating system, your C compiler also creates another definition called <code>__unix__<\/code>.<\/p>\n\n\n\n<p>Every Unix platform that I\u2019ve used follows this standard, although different systems and C compilers might use a single underscore, or no underscore at all. On DOS, C compilers define a similar macro, usually <code>__DOS__<\/code> to recognize the system as DOS, whether that\u2019s FreeDOS, MS-DOS, or another DOS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"programming-across-systems\">Programming across systems<\/h2>\n\n\n\n<p>You can use these definitions in your code to automatically insert specific support for each operating system <em>when compiling your program<\/em>. This is a common method when <em>porting<\/em> an application from one system to another.<\/p>\n\n\n\n<p>Let\u2019s look at a very simple example so we can follow along with what\u2019s going on behind the scenes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main()\n{\n    puts(\"Hello world\");\n\n#if defined(__unix__)\n    puts(\"This is Unix\");\n#endif\n\n#if defined(__linux__)\n    puts(\"Yes, it's Linux\");\n#endif\n\n#if defined(__DOS__)\n    puts(\"We're running on DOS\");\n#endif\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>This uses the <code>#if defined()<\/code> to determine if a macro has been defined by the C preprocessor. It doesn\u2019t matter what the <em>value<\/em> of this macro is, just that it has been defined.<\/p>\n\n\n\n<p>If the system is a Unix-like system, the <code>__unix__<\/code> value will be defined, and the program will add the instruction to print \u201cThis is Unix.\u201d If it\u2019s running on Linux, the C compiler will define <code>__linux__<\/code> so the program can insert the instruction to print \u201cYes, it\u2019s Linux.\u201d On another system, such as AIX or HP-UX, the <code>__linux__<\/code> macro will not be defined, so this instruction won\u2019t get inserted into the program.<\/p>\n\n\n\n<p>On DOS systems, the compiler will instead define the <code>__DOS__<\/code> value, so the program can use that to add the instruction to print \u201cWe\u2019re running on DOS.\u201d This only happens when compiling for DOS systems; this line doesn\u2019t get added to the source code when compiling for another platform like Linux.<\/p>\n\n\n\n<p>Effectively, when compiling on Linux, it\u2019s as though the program\u2019s source code looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main()\n{\n    puts(\"Hello world\");\n\n    puts(\"This is Unix\");\n\n    puts(\"Yes, it's Linux\");\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>If we save this program as <code>hello.c<\/code> and compile it, we will see only those three lines printed to the terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o hello hello.c\n\n$ .\/hello\nHello world\nThis is Unix\nYes, it's Linux<\/code><\/pre>\n\n\n\n<p>Compiling the same program on FreeDOS using OpenWatcom C generates a program that only prints the \u201cHello\u201d and \u201cDOS\u201d lines:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt;wcl -q hello.c\n\n&gt;hello\nHello world\nWe're running on DOS<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"cross-platform-programming\">Cross-platform programming<\/h2>\n\n\n\n<p>Programmers often need to maintain programs that support a variety of targets, not just one. Using these C compiler <em>preprocessor directives<\/em> to detect the operating system can make it easier to support multiple platforms at once. For example, a program might need to support <strong>curses<\/strong> functions when used on Linux or other Unix-like systems, but use the <strong>conio<\/strong> functions to access the console when compiling the same program on FreeDOS.<\/p>\n\n\n\n<p>Check your compiler\u2019s manual for details about how to find the definition for your platform.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using these C compiler preprocessor directives to detect the operating system can make it easier to support multiple platforms at once.<\/p>\n","protected":false},"author":33,"featured_media":2949,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[340,5,150],"tags":[267,91,152],"class_list":["post-8051","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-freedos","category-linux","category-programming","tag-freedos","tag-linux","tag-programming"],"modified_by":"Jim Hall","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8051"}],"version-history":[{"count":1,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8051\/revisions"}],"predecessor-version":[{"id":8052,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8051\/revisions\/8052"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/2949"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8051"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}