能跨平台同时兼容Microsoft Visual Studio和GCC编译器的C语言代码
C语言本来是一个跨平台的语言,但是因为各个编译器在实现上有自己的个性,导致实际上的C语言代码不一定是标准的,因此就不一定是能跨平台编译的,所幸的是,只有小部分C语言代码有这样的问题,大部分还是合乎标准且能跨平台编译的。
本文是经过一些琐碎的查找以后,通过条件编译指令解决了windows平台上的visual studio 编译器和linux平台上的gcc编译器所支持的C语言的差异性后,形成的能同时兼容这两种平台的两种编译器的C语言代码,以分别编译出可在两种平台运行的exe文件。
条件编译指令的通用格式
#ifdef _MSC_VER
// c code supported by windows microsoft visual studio compiler
#elif __GNUC__
// c code supported by linux gcc compiler
#endif
头文件
#ifdef _MSC_VER
#include <io.h>
#include <direct.h>
#include <tchar.h>
#include <Windows.h>
#include <wingdi.h>
#include <process.h>
#elif __GNUC__
#include <unistd.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/time.h>
#endif
常用系统类型和函数
#ifdef __GNUC__
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
typedef uint64_t UINT64;
typedef int8_t INT8;
typedef int16_t INT16;
typedef int32_t INT32;
typedef int64_t INT64;
#define sprintf_s snprintf
#define vsprintf_s vsnprintf
#define _chdir chdir
int fopen_s(FILE** ppf, const char* path, const char* mode)
{
if (ppf == NULL) return -1;
*ppf = fopen(path, mode);
if (*ppf == NULL) return -1; else return 0;
}
size_t fread_s(void* buf, size_t buf_size, size_t element_size, size_t element_count, FILE* fp)
{
if (buf == NULL || fp == NULL || element_size <= 0 || element_count <= 0 || buf_size <= 0 || buf_size < element_count * element_size) return -1;
return fread(buf, element_size, element_count, fp);
}
void ZeroMemory(void* p, int size)
{
if (p == NULL || size < 1) return; memset(p, 0, size);
}
int _itoa_s(int value, char* buf, size_t size, int radix)
{
int r = -1;
if (buf == NULL || size < 30) return r;
if (radix == 10) r = sprintf_s(buf, size - 1, "%d", value);
else if (radix == 16) r = sprintf_s(buf, size - 1, "%x", value);
else if (radix == 8) r = sprintf_s(buf, size - 1, "%o", value);
return r;
}
#endif
文件路径分隔符
#ifdef _MSC_VER
char IdealandPathSep = '\\';
char IdealandPathSep2 = '/';
#elif __GNUC__
char IdealandPathSep = '/';
char IdealandPathSep2 = '\\';
#endif
文字编码
void idealand_set_encoding()
{
#ifdef _MSC_VER
system("CHCP 65001");
#endif
setlocale(LC_ALL, "en_US.UTF-8");
}
获取时间
double idealand_time_get(IdealandTime *ptime)
{
int r = 0;
#ifdef _MSC_VER
SYSTEMTIME currentTime; GetSystemTime(¤tTime);
ptime->year = currentTime.wYear;
ptime->month = (INT8)currentTime.wMonth;
ptime->day = (INT8)currentTime.wDay;
ptime->hour = (INT8)currentTime.wHour;
ptime->minute = (INT8)currentTime.wMinute;
ptime->second = (INT8)currentTime.wSecond;
ptime->msecond = (INT16)currentTime.wMilliseconds;
#elif __GNUC__
time_t now; time(&now); struct tm parts, *p=&parts; gmtime_r(&now, p); //把日期和时间转换为格林威治(GMT)时间的函数
// p = localltime(&timep); //此函数获得的tm结构体的时间,是已经进行过时区转化为本地时间
struct timeval te; gettimeofday(&te, NULL);
ptime->year = 1900 + p->tm_year;
ptime->month = 1 + p->tm_mon;
ptime->day = p->tm_mday;
ptime->hour = p->tm_hour;
ptime->minute = p->tm_min;
ptime->second = p->tm_sec;
ptime->msecond = te.tv_usec/1000;
ptime->usecond = te.tv_usec;
//printf("Weekday: %d\n", p->tm_wday);
//printf("Days: %d\n", p->tm_yday);
//printf("Isdst: %d\n", p->tm_isdst);
#endif
return 0;
}
获取exe文件的路径
char* get_exe_path()
{
char *r=NULL; int got=0;
#ifdef _MSC_VER
got=(_get_pgmptr(&r)==0);
#elif __GNUC__
r=(char *)malloc(IdealandMaxPathLen); if(r==NULL) return NULL;
got=readlink("/proc/self/exe", r, IdealandMaxPathLen-1);
if(got>0) r[got]=0; else got=0;
#endif
if(got) { printf("exe file path = %s\n", r); return r;}
else { printf("cannot get exe path"); return NULL;}
}
查找文件夹中文件名以某字符串开头的第一个文件
#ifdef _MSC_VER
intptr_t fHandle; IdealandFd fd;
if ((fHandle = _findfirst(pattern, &fd)) == -1)
{ idealand_log("cannot find file: %s\n", pattern); return; }
_findclose(fHandle); idealand_log("found file %s\n", fd.name);
#elif __GNUC__
int got = 0; struct dirent* pent; DIR* pd = opendir(collection);
if (!pd) { idealand_log("open collection(%s) failed", collection); return -1; }
while (pent = readdir(pd))
{
if (pent->d_type == DT_DIR || strcmp(pent->d_name, name_start)) { continue; }
else { got = 1; break; }
}
closedir(pd);
#endif
创建文件夹
#ifdef _MSC_VER
r=_mkdir(path);
#elif __GNUC__
r=mkdir(path, 0700); // 0700 means owner can read, write and execute
#endif
多线程
#ifdef _MSC_VER
typedef HANDLE IdealandMutex;
#elif __GNUC__
typedef pthread_mutex_t *IdealandMutex;
#define GetCurrentThreadId pthread_self
#endif
#ifdef _MSC_VER
typedef unsigned (_stdcall* IdealandThreadFunc)(void* pArgs);
#elif __GNUC__
typedef void* (*IdealandThreadFunc)(void* pArgs);
#endif
void idealand_thread_create(IdealandThreadFunc func, void *pArgs)
{
#ifdef _MSC_VER
_beginthreadex(NULL, 0, func, pArgs, 0, NULL);
#elif __GNUC__
pthread_t t1; pthread_create(&t1, 0, func, pArgs);
#endif
}
void idealand_init_mutex(IdealandMutex *p)
{
#ifdef _MSC_VER
*p = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
#elif __GNUC__
*p = (IdealandMutex)idealand_malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(*p, NULL);
#endif
}
void idealand_get_mutex(IdealandMutex mutex)
{
#ifdef _MSC_VER
WaitForSingleObject(mutex, INFINITE);
#elif __GNUC__
pthread_mutex_lock(mutex);
#endif
}
void idealand_release_mutex(IdealandMutex mutex)
{
#ifdef _MSC_VER
ReleaseMutex(mutex);
#elif __GNUC__
pthread_mutex_unlock(mutex);
#endif
}
void idealand_destroy_mutex(IdealandMutex mutex)
{
#ifdef _MSC_VER
CloseHandle(mutex);
#elif __GNUC__
pthread_mutex_destroy(mutex);
#endif
}
socket
#ifdef _MSC_VER
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "AdvApi32.lib")
#elif __GNUC__
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#ifdef __GNUC__
typedef int SOCKET;
typedef const char* PCSTR;
#define INVALID_SOCKET 0
#define SOCKET_ERROR -1
#define closesocket close
int WSAGetLastError() { return errno; }
#endif
#define IdealandSocketTimeoutSeconds 10 // 10 seconds
#ifdef _MSC_VER
const INT32 IdealandSocketTimeout = IdealandSocketTimeoutSeconds * 1000;
#elif __GNUC__
struct timeval IdealandSocketTimeout = { IdealandSocketTimeoutSeconds,0 };
#endif
int idealand_socket_run(IdealandWork awork, IdealandMainArgs* pMargs)
{
int r = 0;
#ifdef _MSC_VER
WSADATA wsaData; // initiate use of WS2_32.dll, makes a request for version 2.2 of Winsock on the system
if (r = WSAStartup(MAKEWORD(2, 2), &wsaData)) { idealand_log("WSAStartup failed: %d\n", r); return -1; }
#endif
if(awork!=NULL) r = awork(pMargs);
#ifdef _MSC_VER
WSACleanup();
#endif
return r;
}