{"id":8245,"date":"2024-10-25T03:00:00","date_gmt":"2024-10-25T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=8245"},"modified":"2024-10-19T14:33:09","modified_gmt":"2024-10-19T18:33:09","slug":"writing-portable-c-programs","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=8245","title":{"rendered":"Writing portable C programs"},"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=\"8245\" 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 class=\"wp-block-paragraph\">The C programming language makes it easy to write powerful, flexible programs. And because you can find C compilers for pretty much any operating system, you can <em>port<\/em> your programs to other platforms. If your program is pretty basic, and only uses the <em>C standard library<\/em> of functions, then porting should be a pretty straightforward process. Just copy your program to the other platform, recompile it, and you\u2019re done.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But if your program requires features specific to one operating system, then you need to consider how to support other systems when writing portable C programs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s where <a href=\"https:\/\/www.both.org\/?p=8051\">using preprocessor directives<\/a> can come in handy. The C preprocessor is part of the compilation process, but you may never really think about it. The preprocessor examines the C source files and takes action on any lines like <code>#include<\/code> to insert the contents of another file at that point. The preprocessor also responds to <code>#define<\/code> directives, to define a <em>constant value<\/em> in a program, such as with this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define PI 3.141<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But the preprocessor can also <em>evaluate<\/em> other things on its own. One neat feature is to determine if certain values have already been defined, and insert code (or not) depending on those values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"know-the-system\">Know the system<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The C preprocessor also defines values for the system that you are compiling for. For example, if you are compiling a program on Linux, the GNU C Compiler will define <code>__linux__<\/code> as a constant. With this value, you can insert code if specific to the Linux operating system, or insert other code if not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check your compiler\u2019s documentation for the values that will be defined for each target platform, but usually these are written with two underscores before and after the value, like <code>__linux__<\/code> for Linux systems, <code>__unix__<\/code> for Unix systems, or <code>__DOS__<\/code> for DOS systems like FreeDOS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, let\u2019s say your program needed to generate a random number between 1 and 100. On Linux, you can use <a href=\"https:\/\/www.both.org\/?p=8051\">the <code>getrandom<\/code> system call<\/a> to let the kernel fill a variable <a href=\"https:\/\/www.both.org\/?p=6874\">with random bits<\/a> like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    int secret;\n    unsigned int randdata;\n\n    getrandom(&amp;randdata, sizeof(int), GRND_NONBLOCK);\n    secret = randdata % 100 + 1;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But that only works on Linux. Other operating systems may not have the <code>getrandom<\/code> system call. To generate a random number from 1 to 100 on these other systems, you might need to \u201cfall back\u201d to the C standard library functions with <code>srand<\/code> to <em>seed<\/em> the random number generator function, usually based on the current time, and <code>rand<\/code> to generate a random value from zero to some very large maximum number:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    int secret;\n\n    srand((unsigned int) time(NULL));\n    secret = rand() % 100 + 1;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can write a more portable version by using <code>#if<\/code> to determine if the <code>__linux__<\/code> value is defined at compile-time, and inserting the appropriate code depending on the system you are compiling for: either Linux or some other platform.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    int secret;\n\n#if defined(__linux__)\n    unsigned int randdata;\n\n    getrandom(&amp;randdata, sizeof(int), GRND_NONBLOCK);\n    secret = randdata % 100 + 1;\n#else\n    srand((unsigned int) time(NULL));\n    secret = rand() % 100 + 1;\n#endif<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"a-portable-number-guessing-game\">A portable number-guessing game<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s see this in practice by writing a <a href=\"https:\/\/www.both.org\/?p=7446\">number-guessing game<\/a> in C that should run on any operating system. When compiling for Linux, the program uses <code>getrandom<\/code> to generate truly random bits. But when compiling for another system like FreeDOS, the program uses <code>srand<\/code> and <code>rand<\/code> to generate pseudo-random values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this \u201cGuess the number\u201d game, the program generates a secret random value between 1 and 100. Then the user must guess the number. At each guess, the program gives the user a hint, printing \u201cToo low\u201d or \u201cToo high\u201d until the user guesses the correct value. For debugging, we\u2019ll also print the secret number at the start of the program:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\n#if defined(__linux__)\n#include &lt;sys\/random.h&gt;\n#else\n#include &lt;time.h&gt;\n#include &lt;stdlib.h&gt;\n#endif\n\nint main()\n{\n    int secret, guess;\n\n#if defined(__linux__)\n    unsigned int randdata;\n\n    getrandom(&amp;randdata, sizeof(int), GRND_NONBLOCK);\n    secret = randdata % 100 + 1;\n#else\n    srand((unsigned int) time(NULL));\n    secret = rand() % 100 + 1;\n#endif\n\n    printf(\"debugging: %d\\n\", secret);\n\n    puts(\"Guess a random number from 1 to 100\");\n\n    do {\n        puts(\"Your guess?\");\n        scanf(\"%d\", &amp;guess);\n\n        if (guess &lt; secret) {\n            puts(\"Too low\");\n        }\n        else if (guess &gt; secret) {\n            puts(\"Too high\");\n        }\n    } while (guess != secret);\n\n    puts(\"That's right!\");\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The program uses <code>#if<\/code> several times. At the start of the source file, the program uses <code>#if<\/code> to include the correct header files: <code>sys\/random.h<\/code> if compiling on Linux, or <code>time.h<\/code> and <code>stdlib.h<\/code> for other systems. Later, the program uses a similar <code>#if<\/code> to insert the appropriate code to generate a random number between 1 and 100.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">During the compilation process, the C preprocessor inserts the appropriate code and replaces constants (like <code>GRND_NONBLOCK<\/code>) with hard-coded values. When compiled on a Linux system, it\u2019s as though the program were written like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int main()\n{\n    int secret, guess;\n\n    unsigned int randdata;\n\n    getrandom(&amp;randdata, sizeof(int), \n                                     0x01\n                                                  );\n    secret = randdata % 100 + 1;\n\n    printf(\"debugging: %d\\n\", secret);\n\n    puts(\"Guess a random number from 1 to 100\");\n\n    do {\n        puts(\"Your guess?\");\n        scanf(\"%d\", &amp;guess);\n\n        if (guess &lt; secret) {\n            puts(\"Too low\");\n        }\n        else if (guess &gt; secret) {\n            puts(\"Too high\");\n        }\n    } while (guess != secret);\n\n    puts(\"That's right!\");\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this case, the <code>0x01<\/code> is the value of <code>GRND_NONBLOCK<\/code> after the C preprocessor expands the named constant into a value.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"lets-play\">Let\u2019s play<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If we save the program as <code>guess.c<\/code> and compile it on a Linux system, the program uses <code>getrandom<\/code> to generate the random secret value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -Wall -o guess guess.c\n$ .\/guess\ndebugging: 81\nGuess a random number from 1 to 100\nYour guess?\n1\nToo low\nYour guess?\n100\nToo high\nYour guess?\n80\nToo low\nYour guess?\n82\nToo high\nYour guess?\n81\nThat's right!<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If we copy the <code>guess.c<\/code> source file to another system, such as FreeDOS, and compile it there, the program compiles the same. But behind the scenes, the program is using <code>rand<\/code> to generate pseudo-random values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; wcl -q guess.c<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>-q<\/code> command line option to the OpenWatcom C Compiler (<code>wcl<\/code>) makes the compiler operate silently. Otherwise, OpenWatcom tends to print lots of extra information that we don\u2019t need to see here.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; guess\ndebugging: 52\nGuess a random number from 1 to 100\nYour guess?\n1\nToo low\nYour guess?\n100\nToo high\nYour guess?\n50\nToo low\nYour guess?\n53\nToo high\nYour guess?\n52\nThat's right!<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"writing-portable-programs\">Writing portable programs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Programmers will need to create programs that support different operating systems. You can\u2019t assume <em>all the world runs Linux<\/em>. But you can make it easier to write portable C programs by using <code>#if<\/code> in your code to detect the target system and use the appropriate code. This method works well for changes that aren\u2019t too large, such as this example of generating a random number using either a Linux system call or the C standard library.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jim shares this follow-up to an earlier article about programming across platforms.<\/p>\n","protected":false},"author":33,"featured_media":3302,"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-8245","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\/8245","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=8245"}],"version-history":[{"count":2,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8245\/revisions"}],"predecessor-version":[{"id":8247,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8245\/revisions\/8247"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/3302"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}