Slashdot Mirror


ANSI C89 and POSIX portability?

LordNite asks: "Here is the situation. I am maintaining a piece of source code which is written in K&R C. One of the original goals of this code was to be as portable as possible to as many platforms as possible. The code runs on UNIX and its clones as well as OS/2. The code avoids POSIX functions such as mmap(2) since at the time it was initially written (early 1990s) POSIX was not very wide spread. The code is well written, but in need of some serious fixing. As I go around fixing parts of the code I would also like to modernize it a bit. Since it is now 2004, can I rely on ANSI C89 and POSIX routines without sacrificing the portability of this code? (Yes, I do realize that the purpose of POSIX is code portability...) I am not really interested in the OS/2 port at this time. I am just interested in keeping portability with UNIX clones. To put my question another way: Are there any UNIX-like OSes in common use, which are currently developed and supported by some entity either OSS or proprietary, that do not support POSIX and ANSI C89?"

26 of 85 comments (clear)

  1. I'd just go with well documented Visual Basic by Clockwurk · · Score: 2, Funny
  2. Use autoconf. by kyz · · Score: 4, Insightful

    Firstly, if you read the entire autoconf manual, you know the intricacies of 90% of these niggling little compatibility differences on every UNIX variant out there.

    Secondly (with automake) it can make a build environment that automatically converts ANSI C to K&R C, if the target install environment only supports K&R C. So don't sweat it. Use mmap() if HAVE_MMAP is defined. Personally, I would abstract file I/O and do all work as abstract file operations. You can then choose after-the-fact whether to fopen()/fread()/fclose() or mmap()/memcpy().

    --
    Does my bum look big in this?
    1. Re:Use autoconf. by kyz · · Score: 2, Insightful

      autoconf is great. It's also fairly obvious if you read the manual. If M4 confuses you, learn it. Not everything has to be C, Perl or Bash syntax.

      autoconf works, autoconf works and autoconf works. Why do you use a configuration-detection script? Because you want your software to work! None of autoconf's "replacements" actually work in all scenarios. What's the point?

      Sure, this one has simpler syntax, or that one makes smaller shell scripts, but they don't work on older or obscure architectures! If I didn't want my code to work on older or obscure architectures, I wouldn't use a configuration utility at all.

      autoconf is still backwards compatible with all its documented macros. Keep using them. There is a conversion script for moving to the "new style" autoconf macros, which make it much easier to integrate with automake. If you used private, undocumented autoconf internals, they're now broken. Tough.

      --
      Does my bum look big in this?
    2. Re:Use autoconf. by aminorex · · Score: 2, Interesting
      "Autoconf works"

      For some value of "works". Autoconf and automake are sorry hacks that should never have been undertaken.

      Instead, there should be one master "config.h" file that infers from the platform headers exactly what HAVE_xxx macros should be defined, and one master "config.c" that abstracts over differences where it is trivial to do so. Everybody shares that, and nobody needs this jiggery-pokery with autoconf, automake, dlltool running recursive m4s. For the love of God, Montressor -- m4!\

      --
      -I like my women like I like my tea: green-
    3. Re:Use autoconf. by Asmodai · · Score: 2, Interesting

      I have to agree.

      I've done autoconf maintenance for some open source projects, I contributed to the auto* projects and my final conclusion is that they are not helping.

      Instead I am just building my own detection code in a similar line as postfix' makedefs does. A lot clearer and keeps your sanity.

      --
      Jeroen Ruigrok/Asmodai
    4. Re:Use autoconf. by statusbar · · Score: 2, Interesting

      Autoconf does not work. It it supposed to dynamically test the platform and figure out the appropriate way to build your app on the system. It tries to do this, but, it all comes down to the fact that it only works on the style of systems that autoconf was written for.

      What do I mean? A big one I hate autoconf for is how cross compiling is broken on almost every one as many compiler tests require the ability to run the code locally. A neat trick I found is that I can cross compile to mingwin32 from linux if linux is on i386 and I have wine installed! But alas, I usually cannot cross compile to mingwin32 from mac osx because the autoconf tests are unable to run the .exe's.

      Another one is how it interacts with slightly different environments like cygwin/mingw/mac osx : .exe files versus .App directories, resource files, etc.

      After originally being a total autoconf convert myself (I have the books!) I decided to roll my own. #ifdefs for the platforms that matter to me, and only those - for only those will be tested anyways. And Makefiles that use the filesystem to decide what files to compile into a library or executable, so nothing needs to change until a new platform is needed.

      --jeff++

      --
      ipv6 is my vpn
  3. Some thoughts... by rjh · · Score: 3, Insightful
    • If it's working, be real careful in how you decide to 'fix' it. The old "if it ain't broke, don't fix it" adage is really true when it comes to old software.
    • Check the original assumptions. Which platforms did it have to run on originally? How many of those vendors are still around? What platforms does it have to run on now? You may discover that the only platforms you need to support all have good POSIX facilities.
    • If you've really got a wild hair to improve things, consider creating a port to $foo (Perl, Python, Java, .NET, etc.). One way to get around the lots of different incompatabilities problem is to use a language which already abstracts these things away, after all.
    • If you absolutely must have platform-specific behavior in C, then GNU Autoconf is probably your best bet. Be warned that GNU Autoconf is arguably a cure that's worse than the disease. I've yet to meet one single programmer who's thought Autoconf was a good idea--only that Autoconf was a marginally less bad idea than all the other alternatives.
    Good luck!
    1. Re:Some thoughts... by runderwo · · Score: 2, Insightful
      You couldn't even compile the Python interpreter on half of the platforms that Autoconf targets.

  4. Purpose? by fm6 · · Score: 2, Insightful
    The code is well written, but in need of some serious fixing. As I go around fixing parts of the code I would also like to modernize it a bit.
    It seems like everybody who posts an Ask Slashdot story these days wants to know how, but hasn't thought about why. In this case, you want to "modernize" the code -- but is there any really good reason for doing so? Is the code hard to maintain in its current form? Are there efficiency issues? You don't say yes or no, but from the way you describe the project, it sounds like the answer is "no". Why risk introducing a bunch of bugs just to make the software "more modern"? Job security, perhaps?
    1. Re:Purpose? by rjh · · Score: 4, Informative

      I've known the submitter for about ten years now, a little less, so maybe I can answer your question for you.

      The reason is simple. He's a hacker. He sees something that works but is inelegant; and he'd like to be able to make it a little more elegant. It's that simple.

      So the answer to "why risk introducing a bunch of bugs just to make the software 'more modern'" is not a facetious "job security".

      The answer is elegance.

      If you can't appreciate that answer, that's a strong sign you're not qualified to have an opinion.

      Please note, by the by, that I almost agreed with you. I recommended that he be very careful in what he fixes and how. That's worlds apart from saying "leave it alone, you don't know what you're doing". Any answer of "leave it alone" is fundamentally anti-hacker.

    2. Re:Purpose? by Omega1045 · · Score: 2, Funny
      That's pretty patronizing. Or maybe the word is fascist.

      Me thinks we have a spy, fellow Slashdotters! This person (parent comment author) sounds more like a drama student than a programmer!

      --

      Great ideas often receive violent opposition from mediocre minds. - Albert Einstein

  5. POSIX and C89 by molo · · Score: 4, Informative

    Ok, POSIX is all about the system calls and C library functions. C89 is about compiler support. They are seperate and don't go hand-in-hand.

    About POSIX and Unix compatibility. There are a handful of Unixes that remain important and widely deployed. They are:

    Solaris
    HP-UX
    AIX
    Linux
    *BSD
    MacOSX

    They pretty much all have modern APIs in recent versions. The older unixes have recently added a bunch of Linux-like modern APIs to make portability easier. This was the reason behind HPUX 11i (the 'i' denotes "internet ready", but what they really mean is glibc/*BSD apis). This is also the reason behind the AIX 5L name (AKA 5.1, 5.2) (L = linux affinity, same deal, new GNU/*BSD apis). You know that MacOSX uses a BSD-based userland, so you're fine there. Then there's Solaris, of which recent versions (>=2.6) are in good shape. Recent versions of the proprietary unixes even have /dev/[u]random and /proc filesystems. There's a lot of common interfaces, as long as you target relatively recent releases.

    Ok, once you figure out what platforms you are targeting, you need to figure out what compilers you will support. All of the proprietary Unixes have their own C compiler (sometimes only available for a fee). Many are not fully ANSI compliant. They are definitely not all C99 compliant. That is the bad news.

    The good news is that gcc is available for all of the major platforms. This is what gcc excels at, it is highly portable. You can use this to your advantage to get things working on these platforms. If your users then want to get them working with other compilers, that is worth a shot too (non-gcc compilers often produce better optimizations, etc.).. but it will be hit or miss.

    Testing. I highly recommend the HP Testdrive program. They make available a bunch of machines with various HP hardware running various operating systems from Linux on Alpha to HPUX on IA64, including Tru64 (aka OSF/1). http://www.testdrive.compaq.com/

    Sourceforge also has a build farm which includes Solaris on sparc and x86 and MacOS X. http://sourceforge.net/docman/display_doc.php?doci d=762&group_id=1#platforms You have to be a developer of a sourceforge project to get access, but its a good deal.

    Good luck. Hope this helps.
    -molo

    HPUX Note: Many people think that 11i is for the Itanium platform. That is not the case. 11i is version 11.11 and higher. 11.11 is for HPPA. 11.20 and higher are for IA64. Both are called 11i.

    --
    Using your sig line to advertise for friends is lame.
    1. Re:POSIX and C89 by Elm+Tree · · Score: 3, Funny

      <SARCASM>

      Wait...
      I think you missed a major version of unix there. In fact the only *real* unix, SCOWare. They even own the copyright on "UNIX".

      </SARCASM>

    2. Re:POSIX and C89 by _|()|\| · · Score: 2, Interesting
      Good advice to actually seek out test platforms. I've found subtle bugs in shell scripts and POSIX-ish C code on certain platforms. Some examples:
      • The ls command returns success on OS X, even if no files were found.
      • The test command has some options, like -e, which are not portable.
      • HP-UX requires an ioctl() to detect that a slave PTY has closed.
      • AIX has fewer than 64 PTYs configured, by default, which exposed a bug in one of my programs.
      • There seems to be disagreement on the types of some socket functions. I have yet to figure out how to get the client's address from accept() without causing a compile warning on at least one platform.
      • Reaping child processes seems to be another mess. The most portable solution I've found is to double fork, letting init clean up the zombies.
      I've started porting a Unix program to Windows and VMS, which has been interesting. For example, Windows and VMS both have a select() function, but it only works on sockets. The popen()/_popen() function on Unix and Windows doesn't redirect stderr, whereas it does on VMS. VMS only lets you get the actual exit status from waitpid() or pclose() in recent versions.
  6. Obligatory book reference by DarkDust · · Score: 2, Informative

    AFAIK really all UNIX and UNIX-like systems support at least POSIX-1988, and most even support SUS1 and higher. Heck, even Windows NT/2000 are (partly) POSIX compatible, and to my knowledge Windows XP can be made POSIX compatible with some extra package from MicroSoft, but I don't know which).

    I really recommend Advanced UNIX Programming, it's an excellent book which not only discusses and explains POSIX and SUS APIs but also where you can expect those APIs to be avaible and how to test for them to be sure. It was also reviewed here at Slashdot.

  7. What part of POSIX? by hubertf · · Score: 2, Informative

    POSIX is not a single specification, but consists of quite a number of parts. While some of the basic interfaces can be considered of widespread use, I wouldn't recommend using others like realtime handling or maybe even threads.

    - Hubert

  8. Not necessarily by squiggleslash · · Score: 2, Interesting
    Believe it or not, there are still K&R systems around. I was somewhat surprised and a little disheartened about six years ago when one of our clients gave us use of a machine where pretty much the only development tools were an old version of Perl and a K&R C compiler - and not a "modernized" just-pre-ANSI one either, I mean something that choked on function prototypes in a way my Sinclair QL's Metacomco C compiler didn't back in 1995...

    In case anyone's interested, this is a HP-UX 11 (the machine is a 9000/800) system, and we can only use it, not administer it, and they pretty much refuse to upgrade anything other than Oracle on it, so we're still stuck with the damned compiler.

    That said, there is a solution: GNU GCC comes with an ANSI to K&R tool. I've not tried it, but it's probably worth playing with. If your ANSI 89 C code can also stay compatable with the translator, then your plans for total compatability should hold up.

    And, of course, some people would argue that K&R was never standard anyway. They're kind of correct, there was a general consensus to how it should work (some of which contradicted the book itself) and most of the incompatabilities were actually extensions, but there will be areas of incompatability whatever you do.

    --
    You are not alone. This is not normal. None of this is normal.
    1. Re:Not necessarily by randombit · · Score: 2, Interesting

      and a K&R C compiler - and not a "modernized" just-pre-ANSI one either, I mean something that choked on function prototypes in a way my Sinclair QL's Metacomco C compiler didn't back in 1995...

      In case anyone's interested, this is a HP-UX 11 (the machine is a 9000/800) system


      That C compiler is (AFAIK) only shipped for building new versions of the kernel. You can also buy a reasonably decent C99/C++98 compiler from HP for about a zillion dollars. The reason they cripple the shipped compiler is to force you to buy the real compiler (or install GCC, of course). So HP isn't really a K&R only system (I mean c'mon, how could you sell a system like that anytime in the last 10 years?), it just ships with a crippled compiler, which is a shame because some people continue to insist that it's usable for anything -- it's not.

    2. Re:Not necessarily by squiggleslash · · Score: 2, Informative
      It's actually not a bad compiler, it's just about 15 years out of date - older if you consider the fact that function prototypes and other nicities were pretty much becoming standard in the late eighties without the help of ANSI.

      It's usable for just about anything except compiling code intended for other systems. I didn't really think, for some reason, about the option of compiling GCC locally (eg into our user account), I may try that and see how far we can get. That would at least also allow us to get around the Perl et al issues too.

      --
      You are not alone. This is not normal. None of this is normal.
  9. HPUX is the CP/M of Unix systems by Anonymous Coward · · Score: 2, Interesting

    You can always try to install gcc in some temp dir. That's what I do on such castrated platforms. It goes a long way to restore sanity.

  10. Plan 9 by Leimy · · Score: 2, Interesting

    Plan 9 is/was the successor to Unix from the people who brought you Unix to begin with.

    It's compiler suites, which approach multiple architectures a little differently, by default don't have hardly and ANSI C or POSIX support. If you need that stuff you have to use the APE frameworks. See this for more information.

    The fact that it's not quite ANSI C and not quite POSIX by default shouldn't discourage you from playing with the OS though or even trying to use it. Apparently the "thin client" trend is coming back and Plan 9 systems support that metaphor quite nicely where everyone has a graphical display and a private hierarchical namespace [each process can have a different namespace in fact]. The OS is meant to be distributed across many nodes, with CPU nodes and File Serving nodes being part of a grid, but you can run it standalone fairly easily as well.

    I've found that even though it doesn't have a great X implementation I can still VNC to other machines that do when I need X and that I can use ssh with their terminal emulator when I need to work with systems Plan 9 can't "mount" or "bind" into my namespace.

    As you can probably tell. I was impressed.

    If you don't want to mess with installing over you existing OS you can try Inferno which installs on Windows, Linux, FreeBSD and even MacOS X [but if you run Panther you will probably need this patched emulator and installer to make it work]. Once done you can build a multi-CPU-architecture grid all your own and learn the "Limbo" programming language and start harnessing those extra CPU cyucles. Inferno also supports thos hierarchical namespaces of Plan 9.

  11. QNX? by calidoscope · · Score: 2, Informative

    QNX is still being used - the latest version now hs gcc support - versus that Watcom compiler for earlier versions (4.25 and earlier).

    --
    A Shadeless room is a brighter room.
  12. Use Samba as a reference by lkaos · · Score: 4, Informative

    We go through great lengths in Samba to be as portable as possible. Our build farm runs the most popular unices on all sorts of architectures (you'd be amazed how different Linux on x86 can be than Linux on say a s390). We support a ton of platforms including some as obscure as the Amiga.

    What I'd do if I were you is to just grep the Samba source code before you use a function. You'll likely find a list of platforms that it doesn't work on, or that simply doesn't have that particular function. You may also find workarounds for bugs in particular implementations.

    --
    int func(int a);
    func((b += 3, b));
  13. Don't use autoconf.... by V.+Mole · · Score: 2, Informative

    ...unless you really want/need to support ancient and obscure platforms. But since the question specifically *said* modern and maintained platforms, then autoconf will just uglify and complicate your code.

    And in answer to the original question: yes, if you're talking modern unix or unix-like systems (i.e. AIX 4.3 or 5, Solaris 7 or later, Linux/glibc or BSD from the last several years, HPUX 11), then yes, you can assume POSIX and C89 (although for AIX, Solaris, and HPUX you'll need to buy a compiler or install GCC).

  14. Go with ANSI C94 and POSIX by Asmodai · · Score: 2, Interesting

    Just do it.

    For both TenDRA and DragonFly we're using ANSI C94 (C90 plus amendments) along with POSIX/SUS and the code in general tends to get cleaner and cleaner (and easier to understand in my opinion).

    It is amazing, since I am doing a lot of these conversions on a plethora of different old time tools, how much programming errors/mistakes the old code managed to get away with...

    --
    Jeroen Ruigrok/Asmodai
  15. Fix yes, Modernize no! by mritunjai · · Score: 2, Insightful

    Hi there,

    You're one of the few still having a job! You've got a project at hand, and you NEED to do it well.

    DO NOT modernize if you don't have to! What you have in your hands is, as you tell, a nice *working* code. IF after your "modernization" crusade, it breaks on some platforms, even due to platform bugs, it will be YOUR neck under the guillotine. Understand THAT!

    And, no, I'm not talking this from my behind... been there, done that, got burned!!! Unnecessary modernization/elegance/optimizations/refactoring is root of all evil and prime cause of job loss! Do your job, and fix whatever is *NEEDED*... and make sure you ain't breaking anything. If you can do THAT much flawlessly, you should be thankful. In software engineering there are just too many variables and you carry the onus of working around them. All compiler/platform/libc bugs will form part of YOUR work... so be careful!

    --
    - mritunjai