DJ音乐盒 | 外置伴侣 | MC词宝盒| SAM机架 | kx3552驱动

一键电音、kx驱动,主播音效软件商业定做

野狼音频科技

咨询QQ:136677098

野狼音频科技软件园

编写C语言跨平台函数(以清屏和休眠函数为例)

作者:野狼音频科技   时间:2015-02-02    浏览:

支持C语言的平台有许多,常见的编译器如VC、gcc、Clang等。不同的编译器共同点是都支持标准C(ANSI C),但是各自却又有自己独立的、平台相关的功能以及函数接口。这通常为程序的移植性带来很多问题。这里我简单谈一下解决方案。

常见思路

常见的解决跨平台移植的思路就是利用 宏。不同编译器有各自不同的宏,宏有很多,具体可以参考编译器的相关手册。通过判断一个宏是否存在来选择性的包含头文件或调用函数,其本质就是一种条件编译。
比如一些平台相关的函数,在不同平台要包含不同文件。

?
1
2
3
4
5
6
<code class="hljs c">#if defined __GNUC__
#include <unistd.h>
#elif defined _MSC_VER
#include <windows.h>
#endif
</windows.h></unistd.h></code>

#if defined 在本例中也可以用#ifdef 替换,但是如果是复杂的条件编译(比如if后面同时判断多个宏),就只能用#if defined 实现了。
__GNUC__是在gcc编译器中定义的宏,_MSC_VER是Windows中VC编译器中的宏。当然了你还可以选择这两个编译器中的其他宏来实现这一功能,只要能确保是两个编译器中平台相关的宏就行。
_MSC_VER这个宏还能判断VC的版本。比如:

?
1
2
3
<code class="hljs c">#if defined(_MSC_VER) && (_MSC_VER >= 1200)
...
</code>

它的意思是如果VC的版本大于VC 6.0,那么...
该宏的详细参考,很容易百度到:

  • MS VC++ 12.0 _MSC_VER = 1800 (Visual C++ 2013)
  • MS VC++ 11.0 _MSC_VER = 1700 (Visual C++ 2012)
  • MS VC++ 10.0 _MSC_VER = 1600(Visual C++ 2010)
  • MS VC++ 9.0 _MSC_VER = 1500
  • MS VC++ 8.0 _MSC_VER = 1400
  • MS VC++ 7.1 _MSC_VER = 1310
  • MS VC++ 7.0 _MSC_VER = 1300
  • MS VC++ 6.0 _MSC_VER = 1200
  • MS VC++ 5.0 _MSC_VER = 1100

    跨平台函数的栗子

    清屏函数

    同样的思路。我们也可以把条件编译用在函数内部。比如要实现控制台的清屏功能,VC中的通常做法是这条语句system("cls");调用控制台的cls命令来清屏。而Linux环境下,给终端清屏是没有cls这一命令的,取而代之的是clear命令。那么如何实现跨平台的清屏功能呢?很简单,依样画葫芦:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <code class="hljs c">void clear()
    {
        #ifdef __GNUC__
        system("clear");
        #elif defined _MSC_VER
        system("cls");
        #endif
    }
    </code>

    这样就有了跨平台的清屏函数clear。但是其实关键都是system函数,两个平台都提供这个函数(system是标准 C里面的函数)。所以可以再改一版。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <code class="hljs c">#if defined __GNUC__
    char *clear = "clear";
    #elif defined _MSC_VER
    char *clear = "cls";
    #endif
    ...
    //当需要清屏的时候
    system(clear);
    </code>

    休眠函数

    无论是gcc还是VC都有休眠函数,不过具体函数接口却不同。

    编译器 头文件 函数名 参数类型 描述
    VC windows.h Sleep unsigned 参数为要休眠的毫秒数
    gcc unistd.h sleep unsigned 参数为要休眠的秒数
    gcc unistd.h usleep unsigned 参数为要休眠的微秒数

    可见,两种环境下的休眠函数的函数名并不相同。并且gcc的两个sleep函数并没有没有提供毫秒级的分辨率。也就是说,比如要休眠200毫秒:

    • Windows中:Sleep(200);
    • Linux中:usleep(200000);

      1秒=1000毫秒,1毫秒=1000微秒

      那么来实现一下跨平台的休眠功能,我提供一种我的方案:

      ?
      1
      2
      3
      4
      5
      6
      7
      <code class="hljs c">#if defined __GNUC__
      #include <unistd.h>
      #define Sleep(x) usleep(x##000)
      #elif defined _MSC_VER
      #include <windows.h>
      #endif
      </windows.h></unistd.h></code>

      这样即使在gcc的编译环境下,我们也有和VC中一样的Sleep函数可以用了。这里我是用宏函数来实现的。#define Sleep(x) usleep(x##000) ##是宏定义里面的连接符,这样就默认给参数后面多加了三个0,即扩大了1000倍。

      gcc 的宏连接符(##)后面不支持连接+ - * /,所以不能写成

      ?
      1
      2
      <code class="hljs c">#define Sleep(x) usleep(x##*1000)
      </code>

      不过VC支持##后面接+ - * /符号。

      掷骰子游戏

      现在,来综合一下刚才的两个函数:清屏和休眠。写一个掷骰子小游戏的demo。

      ?
      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
      <code class="hljs c">#include<stdio.h>
      #include<stdlib.h>
      #include<time.h>
       
      #ifdef __GNUC__
      #include<unistd.h>
      char *clear = "clear";
      #endif
      #ifdef _MSC_VER
      #include<windows.h>
      char *clear = "cls";
      #endif
       
      int a[3];
      //判断是否为顺子
      int isShunzi()
      {
          int max=a[0],min=a[0],sum=a[0];
          for(int i=1;i<3;i++)
          {
              if(a[i]>max)
                  max=a[i];
              if(a[i]<min) else="" int="" mid="sum-max-min;" mid-min="=1&&max-mid==1)" min="a[i];" return="" t="40;//随机40次后结束">=11)
              printf("您的点数是大\n");
          else
              printf("您的点数是小\n");
       
      }</min)></windows.h></unistd.h></time.h></stdlib.h></stdio.h></code>

野狼音频科技软件园