Collection of MSVC gcc compatibility tricks

I just finished the work on the caffe-brewer, an attempt to get the most recent version of caffe building on Windows for my fertilized-forests library. Doing this, I had (again) to find replacements for some undefined gcc functions for VS2012 and decided to collect them here.

The replacements require C++ 11 features and work for Visual Studio 2012 and newer.

Mathematical functions

'isnan' and 'isinf'

Both functions do have a highly efficient version in MSVC. They have been forgotten to be defined as part of std in VS2012, but are included in VS2013. You can safely define them by using

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#if defined(_MSC_VER)
#if _MSC_VER < 1800
namespace std {
  template <typename T>
  bool isnan(const T &x) { return _isnan(x); }

  template <typename T>
  bool isinf(const T &x) { return !_finite(x); }
}
#endif
#endif

'signbit'

Signbit is a very useful and non-trivial to implement function, since it must behave correctly for the special values +/-0, +/-INF and NAN.

Caution: This implementation is not as general as the standard one and only works for a 64 bit architecture using the standardized floating point system.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#if defined(_MSC_VER)
namespace std {
  // Manually implement a signbit function as defined in the standard.
  // It is non-trivial, since it must return valid values for +/-0, +/-inf
  // as well, so the best thing really is to use the bit representation of the
  // floating point numbers. Hence, works only for IEEE floats!
  template <typename T>
  inline static bool signbit(const T &x);
  template <>
  inline static bool signbit<float>(const float &x) {
    return (*reinterpret_cast<const long*>(&x) & (1L << 31)) != 0;
  }
  template <>
  inline static bool signbit<double>(const double &x) {
    return (*reinterpret_cast<const long long*>(&x) & (1LL << 63)) != 0;
  }
}
#endif

'copysign'

Similar to signbit, a very handy function. This one is even included in newer versions of MSVC. This is again an implementation using bit tricks, relying on the signbit implementation given above (and the same disclaimer applies ;) ):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#if defined(_MSC_VER)
#if _MSC_VER < 1800
template <typename T>
inline static T copysign(const T &x, const T &origin);
template <>
inline static float copysign<float>(const float &x, const float &origin) {
  long tmp;
  if (std::signbit(origin)) {
    tmp = *reinterpret_cast<const long*>(&x) | (1L << 31);
    return *reinterpret_cast<float*>(&tmp);
  } else {
    tmp = *reinterpret_cast<const long*>(&x) &
          (std::numeric_limits<unsigned long>::max() >> 1);
    return *reinterpret_cast<float*>(&tmp);
  }
}
template <>
inline static double copysign<double>(const double &x, const double &origin) {
  long long tmp;
  if (std::signbit(origin)) {
    tmp = *reinterpret_cast<const long long*>(&x) | (1LL << 63);
    return *reinterpret_cast<double*>(&tmp);
  } else {
    tmp = *reinterpret_cast<const long long*>(&x) &
          (std::numeric_limits<unsigned long long>::max() >> 1);
    return *reinterpret_cast<double*>(&tmp);
  }
}
#endif
#endif

'round'

round is not available on the Windows platform. The following alternative can be used:

1
2
3
4
5
6
7
8
9
#if defined(_MSC_VER)
// This is an implementation of 'round to int'.
template <typename T>
int round(const T &x) {
  return (x > static_cast<T>(0.)) ?
            (x + static_cast<T>(0.5)) :
            (x - static_cast<T>(0.5));
}
#endif

'__builtin_popcount' and '__builtin_popcountl'

Even the intrinsics have their correspondances on Windows:

1
2
3
4
5
#if defined(_MSC_VER)
#include <intrin.h>
#define __builtin_popcount __popcnt
#define __builtin_popcountl __popcnt64
#endif

OS functions

'getpid'

This function is defined similarly in Windows, but you have to include process.h

'mkstemp' and 'mkdtemp'

These functions can be used on Linux to create temporary files. On Windows, you can use the function tmpnam to get a temporary filename and then create the file or directory with the standard methods, e.g.,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#if defined(_MSC_VER)
  // Use the system method to create temporary files.
  *temp_filename = "C:\\temp" + string(tmpnam(nullptr));
#else
*temp_filename = "/tmp/caffe_test.XXXXXX";
#endif
  char* temp_filename_cstr = new char[temp_filename->size() + 1];
  // NOLINT_NEXT_LINE(runtime/printf)
  strcpy(temp_filename_cstr, temp_filename->c_str());
#if defined(_MSC_VER)
  FILE* fd = fopen(temp_filename_cstr, "w");
  CHECK(fd != NULL) << "Failed to open a temporary file at: " << *temp_filename;
  fclose(fd);
#else
  int fd = mkstemp(temp_filename_cstr);
  CHECK_GE(fd, 0) << "Failed to open a temporary file at: " << *temp_filename;
  close(fd);
#endif
  *temp_filename = temp_filename_cstr;
  delete[] temp_filename_cstr;

'mkdir'

mkdir is available as _mkdir in direct.h, but can not be used in exactly the same way as mkdir on Linux:

1
2
3
4
5
#if defined(_MSC_VER)
    CHECK_EQ(_mkdir(source.c_str()), 0) << "mkdir " << source << "failed";
#else
    CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << "failed";
#endif

'snprintf'

snprintf is an admittedly handy function on Linux, but not in the standard. You can emulate it like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#if defined(_MSC_VER)
// Compare to http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
#include <stdarg.h>
#define snprintf c99_snprintf
inline static int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
  int count = -1;
  if (size != 0)
      count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
  if (count == -1)
      count = _vscprintf(format, ap);
 return count;
}
inline static int c99_snprintf(char* str, size_t size, const char* format, ...) {
  int count;
  va_list ap;
  va_start(ap, format);
  count = c99_vsnprintf(str, size, format, ap);
  va_end(ap);
  return count;
}
#endif

'usleep'

The functionality of usleep, provided by unistd.h is not required anymore with C++ 11. It can be emulated like:

1
2
3
4
5
6
7
#if defined(_MSC_VER)
#include <chrono>
#include <thread>
inline static void usleep(const int64_t &t) {
  std::this_thread::sleep_for(std::chrono::microseconds(t));
}
#endif

 

Update (04/01/2015): added compatibility for VS2013 and added consistent guards.

Comments

Tags

Archive

Archive