问题根因
微软的visual studio 2015的VC编译器及以上版本都是支持大部分c11语法标准的,但在具体实现和工作原理上与GCC/G++依然有不少出入,导致即便写的代码是一致的,得到的结果却天差地别。甚至有时根本在另一平台上无法运行。
案例展示
#ifdef _WIN32
#define PRV_DPT_LOGI(fmt, ...) fprintf(stdout, "PRV_DPT I: " fmt "
", __VA_ARGS__)
#define PRV_DPT_LOGW(fmt, ...) fprintf(stdout, "PRV_DPT W: " fmt "
", __VA_ARGS__)
#define PRV_DPT_LOGE(fmt, ...) fprintf(stdout, "PRV_DPT E: " fmt "
", __VA_ARGS__)
#else
#define PRV_DPT_LOGI(...) __android_log_print(ANDROID_LOG_INFO, "PRV_DPT", __VA_ARGS__)
#define PRV_DPT_LOGW(...) __android_log_print(ANDROID_LOG_WARN, "PRV_DPT", __VA_ARGS__)
#define PRV_DPT_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "PRV_DPT", __VA_ARGS__)
#endif
#ifdef _WIN32
#define FAIL_EXIT(code) {system("pause");exit(code);}
#else
#define FAIL_EXIT(code) {exit(code);}
#endif
// the incorrect version
// Ok on Linux/Android, but failed on Windows: incomplete bytes are read.
void read_yuv_file(uint8_t * y_plane,
uint8_t * uv_plane,
uint64_t y_size,
uint64_t uv_size,
const char * file){
std::fstream fs(file, std::ios::in);
if (!fs.is_open()) {
PRV_DPT_LOGI("failed to open file [%s]!", file);
FAIL_EXIT(-1);
}
fs.read((char*)y_plane, y_size);
uint64_t n_read = fs.gcount();
if (n_read < y_size) {
PRV_DPT_LOGE("read_yuv_file failed: expected %lu bits, got %lu!", y_size, n_read);
FAIL_EXIT(-1);
}
fs.read((char*)uv_plane, uv_size);
n_read = fs.gcount();
if (n_read < uv_size) {
PRV_DPT_LOGE("read_yuv_file failed: expected %lu bits, got %lu!", uv_size, n_read);
FAIL_EXIT(-1);
}
fs.close();
}
上述代码在Linux/Android平台上是可以正确工作的,可以完整的将YUV格式的数据读取到对应的指针所指向的内存中;
但当移植至windows平台上时,在visual studio 2015上却报错:
PRV_DPT E: read_yuv_file failed: expected 691200 bits, got 0!
program exit with code 0xffffff.
显示文件读取不正确,读取到的字节数量为0。
这是因为默认情况下,GCC默认读取格式是binary二进制流,而visual studio的vc则为text文本字符格式。
因此,将缺省的默认读取格式指定清楚就可以跨平台无区别运行了。
更正后的代码如下:
#ifdef _WIN32
#define PRV_DPT_LOGI(fmt, ...) fprintf(stdout, "PRV_DPT I: " fmt "
", __VA_ARGS__)
#define PRV_DPT_LOGW(fmt, ...) fprintf(stdout, "PRV_DPT W: " fmt "
", __VA_ARGS__)
#define PRV_DPT_LOGE(fmt, ...) fprintf(stdout, "PRV_DPT E: " fmt "
", __VA_ARGS__)
#else
#define PRV_DPT_LOGI(...) __android_log_print(ANDROID_LOG_INFO, "PRV_DPT", __VA_ARGS__)
#define PRV_DPT_LOGW(...) __android_log_print(ANDROID_LOG_WARN, "PRV_DPT", __VA_ARGS__)
#define PRV_DPT_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "PRV_DPT", __VA_ARGS__)
#endif
#ifdef _WIN32
#define FAIL_EXIT(code) {system("pause");exit(code);}
#else
#define FAIL_EXIT(code) {exit(code);}
#endif
// the correct version
// Working great on both Linux/Android and Windows.
void read_yuv_file(uint8_t * y_plane,
uint8_t * uv_plane,
uint64_t y_size,
uint64_t uv_size,
const char * file){
std::fstream fs(file, std::ios::in|std::ios::binary);
if (!fs.is_open()) {
PRV_DPT_LOGI("failed to open file [%s]!", file);
FAIL_EXIT(-1);
}
fs.read((char*)y_plane, y_size);
uint64_t n_read = fs.gcount();
if (n_read < y_size) {
PRV_DPT_LOGE("read_yuv_file failed: expected %lu bits, got %lu!", y_size, n_read);
FAIL_EXIT(-1);
}
fs.read((char*)uv_plane, uv_size);
n_read = fs.gcount();
if (n_read < uv_size) {
PRV_DPT_LOGE("read_yuv_file failed: expected %lu bits, got %lu!", uv_size, n_read);
FAIL_EXIT(-1);
}
fs.close();
}