首页 编程 C/C++ 查看内容

能跨平台同时兼容Microsoft Visual Studio和GCC编译器的C语言代码

2022-2-17 12:37 2755 0

摘要: C语言本来是一个跨平台的语言,但是因为各个编译器在实现上有自己的个性,导致实际上的C语言代码不一定是标准的,因此就不一定是能跨平台编译的,所幸的是,只有小部分C语言代码有这样的问题,大部分还是合乎标准且 ...
关键词: ifdef mutex endif include typedef idealand ptime GNUC elif return

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 
#include 
#include 
#include 
#include 
#include 

#elif __GNUC__

#include 
#include 
#include 
#include 

#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 
  #include 
  #pragma comment(lib, "Ws2_32.lib")
  #pragma comment(lib, "Mswsock.lib")
  #pragma comment(lib, "AdvApi32.lib")
#elif __GNUC__
  #include 
  #include 
  #include 
  #include 
#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;
}

本文出处: https://www.toutiao.com/a7065195893342945824/
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部