Porting C/C++ to/from Win32 & Unix - A C/C++ Rosetta Stone

The following few tables and notes are a few that were compiled during the process of porting Qu-Prolog from Unix to Win32. They are by no means complete, and probably inaccurate in a few details, but I have found them to be a great help when porting software in either direction.

Please note that threading is not discussed, as the ported application that these notes are based on contains its own scheduler and threading implementation.

Update: If you're interested in porting applications with threading, check out the pThreads-Win32 Project.

#include Porting Lookup Table:

Unix: Windows:
unistd.h io.h
fcntl.h (Defines SIGINT etc. - no prototypes)
Also (Varies):
signal.h
windows.h (GetCurrentProcess(), other system calls)
direct.h
times.h time.h
Any network includes winsock.h
(With typedef int socklen_t;)

Code and Function Porting Lookup Table:

Unix: Windows: Explanation:
getopt(argc, argv, opts) getopt(argc, argv, const_cast(opts)) Use XGetOpt from: http://www.codeproject.com/cpp/xgetopt.asp - It's VERY useful (and public domain).
pipe(fdes); _pipe(fdes, 256, _O_BINARY); Pipes under windows are complex. Check out the migration guide.
kill(pid, exitcode) TerminateProcess(handle, exitcode) These calls require windows.h to be included.
getpid() GetCurrentProcess() This returns a handle suitable for TerminateProcess()
struct tms usage; 
times(&usage);
int32 msec;
msec = (usage.tms_utime 
      + usage.tms_stime) 
      * 1000 / CLK_TCK;
clock_t msec;
msec = clock() * 1000 / CLOCKS_PER_SEC;
times() doesn't exist, and CLK_TCK became CLOCKS_PER_SEC as of about Visual C++ 5.0
chdir() _chdir() The underscore.
getcwd() _getcwd() The underscore.
errno == EINPROGRESS (errno = WSAGetLastError() == WSAEINPROGRESS)
&& errno == WSAEWOULDBLOCK
Windows sockets work differently at a lower level wrt blocking.
gettimeofday(struct timeval* tp, void* tzp) Create a Function:
int gettimeofday
      (struct timeval* tp, void* tzp) {
    DWORD t;
    t = timeGetTime();
    tp->tv_sec = t / 1000;
    tp->tv_usec = t % 1000;
    /* 0 indicates success. */
    return 0;
}
Just a replacement for a common call.
mkstemp() _mktemp() This makes a temporary file name from a "tempXXXX", replacing X's with numbers. Windows is apparently limited to a max of 27 unique names.
__PRETTY_FUNCTION__ __FUNCDNAME__ Visual C++ just must be different...
setitimer() SetTimer() Look up the man page for setitimer and MSDN docs for the non MFC SetTimer(). If you're using either of these, hopefully you know what you're doing!
ifstream ifstrm(file) ifstream ifstrm(file, ifstream::binary) Attempting to read a binary file, this works under Unix, but destroys Windows' EOF detection.
fopen(FILE *fp, "r") fopen(FILE *fp, "rb") Attempting to read a binary file, this works under Unix, but destroys Windows' EOF detection.
cerr.form("Integer %d", int i) printf("Integer %d", int i) Windows doesn't appear to have ostream.form(), so use printf()


Miscellaneous Notes:

Benchmarks using native Win32 Code:

It was previously mentioned that Cygwin caused a 40% decrease in performance using benchmarks under both Windows and Unix. The native port, however, showed no noticeable performance decrease whatsoever in the benchmarks used.

Making TCP Work:

Unlike under Unix, before a socket created on Windows using the WinSock library is used, it must be initialized using the following call:

WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData );

Once this code is executed, then socket operations may be used. Without it, you get an error code of 10093 (“Either the application has not called WSAStartup, or WSAStartup failed.”)

Another potential problem is with conflicts between the platform SDK and WinSock2. Originally, we had not planned to use WinSock2, as there was no need for any of the additional API calls; however, as the Elvin Libraries depended on WinSock2, we decided that we should use to avoid difficulties. This, however, caused problems itself. Duplicate definitions occured for many structs and method prototypes. A solution for this was to make sure that these headers were always included in the following order, with the #define always added.

#include <winsock2.h>
#define WINSOCKAPI
#include <windows.h>

Polling for Input on a File Descriptor - Making sure a read() won't block:

Under Unix, select() works on all types of file descriptors. Under Win32, however, select() only works on file descriptors from Winsock - ie: select() can only poll sockets. This caused/is causing major problems with polling stdin and file descriptors on files which are handled in Qu-Prolog with low C-level calls (eg: open() and friends). Instead of file descriptors, windows uses handles instead for this type of code. In order to obtain a handle from a file descriptor, the following code is used: handle = (HANDLE)_get_osfhandle(fd) Depending on whether we're polling a set of file descriptors or a single file descriptor, there are two separate functions that we can use:

  • result = WaitForMultipleObjects(hcount + 1, handles, true, NULL)
  • result = WaitForSingleObject(fd,0)

Comments