Code portability basically refers to making source code able to compile on different platform without making any changes in source code.
While coding its very important to keep portability in mind.The best way to introduce code portability is while coding.Keeping certain things into account we can achieve code portability with lesser effort, which we will discuss in this post.There are certain tools too which detect portability problems on source code, its a post processing of code and requires extra effort.
Non-portable code introduces problems like maintenance of different versions, reduces readability, reduces understanding of code etc...
Efforts needs to make legacy or old source code portable, can really make you feel lost in this big programming ocean. So, the best policy is to keep portability into account while writing code, it saves lots of time and efforts on rework. Big question now is - "How to write portable code?".Our source code should be compatible with different environment like different processor, different OS, different version of libraries etc... In this post we would focus on basic tips need to be kept in mind while writing code.

1) Don't assume data type size to be constant across platform, as it may change with platform.
Many a times programmers makes a common mistake by assuming size of pointer and long same.If in some expression sizeof(long) is used, it may give different result on 32-bit and 64-bit OS version. Like if we talk about Microsoft Visual Studio running on 64-bit OS version the pointer size would be 8 byte and size of long comes out to be 4 byte. Program written with such assumption would give false result or may even get crash.So, one has to be very cautious while using data type size across the platform.

2) Don't use specific system constant.
System specific constant should not be used as they are not portable, we are some time not aware of them also. Like system constant "NULL" is specific to windows and will give compilation error on other platform. Instead of "NULL" one can use "0".

3) System file/folder path notation may vary on different platform.
When working with file path one need to be cautious for example "c:\\TestFile.txt" will work on Windows but give error on Linux.For this one i recommend to use forward slash "c://TestFile.txt" , it would work well on both windows and Linux.

4) Avoid using system specific models/libraries.
Don't use system specific models/libraries like Event handling model, Threading libraries, File Creation libraries etc.. . As they are not compatible across platform. Write a wrapper around such models and within wrapper use generic portable libraries. For example, Windows even handling model is totally different from Linux. Windows have special mode for handling events, like we may not find timed wait for multiple object on other platform.

5) Always write default statement in switch case.
Many latest compiler gives compilation error if default is not specified.

6) Always specify return type for functions.
Many latest compiler gives compilation error if return type is not specified.

7) Always specify type with static variables.
Variables declared with static keyword must contain data type with it, some old compiler take int as default type but modern compiler will generate compilation error for it.

8) Always take care of scope of variable.
Like some compiler support variable scope limited to for() while some compiler dont.
For example:-
Don't prefer writing code as below (Non-portable code).

{
           for(int i ; ;)
          {
          //do some thing
           }


           for(int i ; ;)
         {
          //do some thing
          }

        }


         Prefer writing code as below (Portable code)
        {
           for(int i ; ;)
          {
          //do some thing
           }

           for(int j ; ;)
         {
          //do some thing
          }

        }

9) Don't use C++ commenting style in C code.
Don't use // commenting style in c code, as compile other then microsoft visual studio may generate error for it. Prefer using /* */ commenting style.

10) Take care of include depth for header files and also for file code size.
Microsoft visual studio compiler generated error like "internal compiler error" if include depth is too large or file size exceeds certain limit. Always take care of file size and include depth.

I have tried to cover 10 basic tips for code portability for beginners though there are several other areas too, where we need to focus on advanced portability issues, for e.g. dealing with classes, virtual functions, exception handling, compiler directives, run-time identification. I will cover this topic separately bye for now.

Hope you enjoyed this post ! <<plug removed>>

Keep Rocking
-Tajendra

Recommended Answers

All 15 Replies

2) Don't use specific system constant.
System specific constant should not be used as they are not portable, we are some time not aware of them also. Like system constant "NULL" is specific to windows and will give compilation error on other platform. Instead of "NULL" one can use "0".

NULL is standard, not system-specific.

3) System file/folder path notation may vary on different platform.
When working with file path one need to be cautious for example "c:\\TestFile.txt" will work on Windows but give error on Linux.For this one i recommend to use forward slash "c://TestFile.txt" , it would work well on both windows and Linux.

I use forward slash too (I do it correctly, though).

6) Always specify return type for functions.
7) Always specify type with static variables.
8) Always take care of scope of variable.

Dealing with nonstandard, prestandard stuff -- yeah. Don't write code for 1988. :P

I have been doing programming in C and C++ for two years. I fetch so many problems regarding to global variable and function prototype as well as return value. Try to do coding less complexity as possible as you can. use function to create a task.

NULL is not preferred.

Words from Bjane Stroustrup :-
Should I use NULL or 0?

In C++, the definition of NULL is 0, so there is only an aesthetic difference. I prefer to avoid macros, so I use 0. Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer. In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days.

If you have to name the null pointer, call it nullptr; that's what it's going to be called in C++0x. Then, "nullptr" will be a keyword.

Also Proper C style is to use the macro NULL (#defined in stddef.h), whereas proper C++ style is simply to use 0.

>NULL is not preferred.
Nice backtrack, but preference is not truth. Bjarne Stroustrup is well known for disliking certain features inherited from C, and macros are one of those features. It doesn't mean that NULL is wrong in any way. Let's address his concerns:

Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer.

Note that this is the first real problem he's mentioned. Prior to that it was a stated fact that the difference between NULL and 0 is aesthetic, and an opinion that he prefers to avoid macros. Neither of these are problems. This problem has nothing to do with the macro, it's a misunderstanding of pointers and the null pointer specifically. Whether you use NULL or 0, it'll confuse someone who doesn't understand how the null pointer constant works.

In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided.

For the same reason C programmers don't worry about conforming to pre-standard compilers unless they're actually using one, C++ programmers should be more concerned with conforming to standard C++ first. In standard C++, the definition of NULL specifically excludes the "something unsuitable" that Stroustrup was implying[1].

Also Proper C style is to use the macro NULL (#defined in stddef.h)
NULL is defined in <stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>, <locale.h>, and <wchar.h>. For C++ you can also use the <c*> header names.

whereas proper C++ style is simply to use 0.
You use "proper style" in the wrong sense. This is a controversial issue (much like bracing styles) where both options are equally good and you'll find that opinions are fairly equally split. Just because you're a Bjarne-style fan doesn't mean everyone else is. ;)

[1] #define NULL ((void*)0)

Want to add one more point here in this discussion.
"0" create less confusion, if we write "NULL" then again we have to check its definition moving across different platforms. Where as using "0" creates no confusion.

Another debate between hen and egg :)
who was the first to be there? ;)
If it is a matter of style, is it worth of debate?
anyway it is like

int main(){
//.............
}

and

int main()
{
//.............
}

which is good?

Want to add one more point here in this discussion.
"0" create less confusion, if we write "NULL" then again we have to check its definition moving across different platforms. Where as using "0" creates no confusion.

You really need to read what others are telling you and stop being so dense. The Standard says that NULL is defined as 0, it is not a system thing at all, it's a compiler thing. As long as your compiler is standards-compliant, your platform is irrelevant.

[edit]
P.S. Don't bother rebutting, I'm not looking at this thread again. It's going to turn into a flame war and I won't be a part of it.

>if we write "NULL" then again we have to check its definition moving across different platforms
No, we don't. NULL is just as well defined in C++ as it is in C. You're making the common mistake of assuming that NULL supports the same possible definitions in C++ as it does in C despite the change to implicit pointer conversion semantics in C++. Language standardization isn't that haphazard. There are clauses in the standard that specifically prohibit definitions of NULL that would cause a problem.

>Where as using "0" creates no confusion.
BS. The most common confusion created by using 0 is "are we working in a pointer context or a numeric context?":

#include <cstddef>
#include <iostream>

void foo(int x)
{
  std::cout<<"Numeric context\n";
}

void foo(int *p)
{
  std::cout<<"Pointer context\n";
}

int main()
{
  /*
    Fix the bug.
    Is a cast needed or not?
  */
  foo(0);    // 1) Hmm, pointer or numeric?
  foo(NULL); // 2) Very likely to be pointer
}

0 hides the author's intention while NULL highlights it. That's one of the benefits that manifest constants give you. In option 1, you simply don't know which overload the author intended. The bug becomes much harder to fix, if it's even a bug. In option 2 (assuming the author was properly using NULL only in pointer context), you can tell at a glance what was intended and can fix the bug with a cast:

foo((int*)NULL);

I have no problem with you advocating your preference (I prefer to use 0 myself), but please don't make misleading arguments.

I'm not looking at this thread again.

Ha! Made you look!

It's going to turn into a flame war and I won't be a part of it.

No it's not. It's a healthy (but old) discussion between professionals. People can disagree without calling each-other names you know?

commented: Good points. +10

I tend to go with neither 0 nor NULL. :P
http://c-faq.com/null/ptrtest.html

I agree. But I still need NULL/0 for assignment of values, or return-values. And I use both, whatever looks the most logical for the situation.

want to add some more tips, which is also an important one.
Do not use carriage return in portable code.

On unix systems, the standard end of line character is line feed ('\n'). The standard on many PC editors is carriage return and line feed ("\r\n"), while the standard on Mac is carriage return ("\r"). The PC compilers seem to be happy either way, but some Unix compilers just choke when they see a carriage return (they do not recognize the character as white space). So, we have a rule that you cannot check in carriage returns into any cross platform code. This rule is not enforced on the Windows front end code, as that code is only ever compiled on a PC. The Mac compilers seem to be happy either way, but the same rule applies as for the PC - no carriage returns in cross platform code.

want to add some more tips, which are also an important one.
a) Do not use carriage return in portable code.

On unix systems, the standard end of line character is line feed ('\n'). The standard on many PC editors is carriage return and line feed ("\r\n"), while the standard on Mac is carriage return ("\r"). The PC compilers seem to be happy either way, but some Unix compilers just choke when they see a carriage return (they do not recognize the character as white space). So, we have a rule that you cannot check in carriage returns into any cross platform code. This rule is not enforced on the Windows front end code, as that code is only ever compiled on a PC. The Mac compilers seem to be happy either way, but the same rule applies as for the PC - no carriage returns in cross platform code.

b) Initializer lists with objects will not work with all compilers
Don't use initializer lists with objects, as its a non portable code.

>Do not use carriage return in portable code.
>b) Initializer lists with objects will not work with all compilers

Alright, I let the carriage return advice slide, but now you're being too cryptic for useful advice. Give specifics and examples, please.

Some more tips:-

Be careful while including header file names.

1) Do not include file name assuming it to be case insensitive.
Some operating systems, such as DOS, Windows NT and Vax-VMS,
do not have case-sensitive file names. When writing programs to
such operating systems, the programmer can include a file in many
different ways.
If you are inconsistent, your code will be difficult to port to an
environment with case-sensitive file names. Therefore you should
always include a file as if it was case sensitive.

Suppose You have filename "MyTest.h"

//Case-sensitivity of header file name
// Includes the same file on Windows NT, but not on UNIX.
#include "MyTest.h" //portable example

#include "Mytest.h" // non-portable example, since you have not        specified case sensitive name, 
#include "Mytest.H"  // non-portable example

2) Do not use pragma's
A pragma is usually a way to control the compilation process, such
as disabling optimization of a particular function, or to force an
inline function to become inline in cases when the compiler normally
would refuse to make it inline.
Everything about pragmas is implementation-defined, so they are
perhaps the most non-portable feature of C++. The preprocessor will
handle them if it can understand them, and otherwise they will just
be ignored. You cannot be completely sure a new compiler will
understand any pragmas in your code.
It is only OK to use pragmas as long as your code will work correctly
without them. Therefore you should only use them sparingly and
always document why and where they are used. You have to be very cautious while using pragma's.

A pragma-directive
The pragma once was previously provided by the g++ compiler as a way for the programmer
to tell the preprocessor which files that are include files. Files with the
pragma should only be included once.

#pragma once /* NO: not portable! */
commented: Tip: Don't add more tips until you've clarified the previous ones. -4
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.