Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should "portable" C compile as C++?

I got a comment to an answer I posted on a C question, where the commenter suggested the code should be written to compile with a C++ compiler, since the original question mentioned the code should be "portable".

Is this a common interpretation of "portable C"? As I said in a further comment to that answer, it's totally surprising to me, I consider portability to mean something completely different, and see very little benefit in writing C code that is also legal C++.

like image 630
unwind Avatar asked Apr 03 '09 08:04

unwind


People also ask

Is compiled C code portable?

C compilers generate machine code which is portable only to a very limited extent, between machines of the same processor/memory architecture and OS.

What does it mean for C to be portable?

C is a portable programming languageIf you write a C code in your machine, it will run on any machine which supports C, without modifying a single line of code. Because it is not tied to any hardware or system. We can say, it is a hardware independent language or platform independent language.

Is C more portable than C++?

C is much more portable. Good C++ compilers exist only for the most popular platforms, while C compilers exist for just everything, even the most exotic hardware / OSes.

Why is C not a portable language?

C is not portable because not only is it tied to a specific OS in many cases, it is also always tied to a specific hardware architecture once it has been compiled.


1 Answers

The current C++ (1998) standard incorporates the C (1989) standard. Some fine print regarding type safety put aside, that means "good" C89 should compile fine in a C++ compiler.

The problem is that the current C standard is that of 1999 (C99) - which is not yet officially part of the C++ standard (AFAIK)(*). That means that many of the "nicer" features of C99 (long long int, stdint.h, ...), while supported by many C++ compilers, are not strictly compliant.

"Portable" C means something else entirely, and has little to do with official ISO/ANSI standards. It means that your code does not make assumptions on the host environment. (The size of int, endianess, non-standard functions or errno numbers, stuff like that.)

From a coding style guide I once wrote for a cross-platform project:

Cross-Platform DNA (Do Not Assume)

  • There are no native datatypes. The only datatypes you might use are those declared in the standard library.
  • char, short, int and long are of different size each, just like float, double, and long double.
  • int is not 32 bits.
  • char is neither signed nor unsigned.
  • char cannot hold a number, only characters.
  • Casting a short type into a longer one (int -> long) breaks alignment rules of the CPU.
  • int and int* are of different size.
  • int* and long* are of different size (as are pointers to any other datatype).
  • You do remember the native datatypes do not even exist?
  • 'a' - 'A' does not yield the same result as 'z' - 'Z'.
  • 'Z' - 'A' does not yield the same result as 'z' - 'a', and is not equal to 25.
  • You cannot do anything with a NULL pointer except test its value; dereferencing it will crash the system.
  • Arithmetics involving both signed and unsigned types do not work.
  • Alignment rules for datatypes change randomly.
  • Internal layout of datatypes changes randomly.
  • Specific behaviour of over- and underflows changes randomly.
  • Function-call ABIs change randomly.
  • Operands are evaluated in random order.
  • Only the compiler can work around this randomness. The randomness will change with the next release of the CPU / OS / compiler.
  • For pointers, == and != only work for pointers to the exact same datatype.
  • <, > work only for pointers into the same array. They work only for char's explicitly declared unsigned.
  • You still remember the native datatypes do not exist?
  • size_t (the type of the return value of sizeof) can not be cast into any other datatype.
  • ptrdiff_t (the type of the return value of substracting one pointer from the other) can not be cast into any other datatype.
  • wchar_t (the type of a "wide" character, the exact nature of which is implementation-defined) can not be cast into any other datatype.
  • Any ..._t datatype cannot be cast into any other datatype

(*): This was true at the time of writing. Things have changed a bit with C++11, but the gist of my answer holds true.

like image 99
DevSolar Avatar answered Sep 18 '22 12:09

DevSolar