• 用宏实现C/C++从非零整数开始的数组


      相信大家在刚学习C/C++时,都会对数组下标从0开始编号有疑惑。尽管我是喜欢从0开始编号的“0党”,但是也有很多的人是喜欢从1开始编号。

      意识到C/C++数组与指针具有一定的相似性后,我开始构思如何仿造Pascal实现类似于array[1..100]这样的声明方法。

      今天和大神gjs讨论后,他给出第一个实现方案:

    int buf[100];
    int a[100];
    a = buf + 10;    //等价于a = &b[10]

      这样目的是访问a[0]的时候相当于访问b[10],因此a[-10]相当于访问b[0],这样我们可以通过访问a来访问buf,相当于得到一个从-10开始,长度为100的数组。

      可惜的是,编译不通过。听说是数组不能作为左值。

      因此我们改用指针实现。

      

    int buf[100];
    int *a = buf + 10;
    a[-3] = 3;

      编译成功。

      我们决定改写成宏。

    #define array(type, name, lb, ub) type buf[ub - lb + 1]; type* name = buf - lb

      这样,我们就可以使用array(int, abc, -5, 5)来声明一个下标范围为-5到5的“数组”。

      似乎是没有问题了。

      不过,遇到多个array声明就有问题了:

    int main(){
        array(int, a, 1, 100);
        array(int, b, -1, 1);
    }

      编译器抗议了:

    10:5: error: conflicting declaration 'int buf [3]'
    9:5: error: 'buf' has a previous declaration as 'int buf [100]'

      这是由于使用了两个临时变量造成的。展开定义:

    int buf[100 - 1 + 1]; int* a = buf - 1;
    int buf[1 - -1 + 1]; int* b = buf - -1;

      声明了两个buf!

      为了解决这一问题,我们使用这样的方法:改名。

      这是新的array声明:

      

    #define array(type, name, lb, ub) type name##buf[ub - lb + 1]; type* name = name##buf - lb

      注意到##号了吗?这是连接的意思。这样,他们展开后就得到了:

    int abuf[100 - 1 + 1]; int* a = abuf - 1;
    int bbuf[1 - -1 + 1]; int* b = bbuf - -1;

      当然,这并不能保证没有bug。比如说我又声明了一个char abuf[30]。

      最好的方法是将它改复杂一些,再加上大量的随机字符,然后还要加上文件名、行数,将冲突的可能性改到最小。当然,故意作死的人我们也拦不住。

      好了,现在使用是一点问题都没有。但是使用memset的话……

      你可能会说“不就是不用memset(a, 0, sizeof a),而用memset(a + lb, 0, sizeof a)嘛,有什么不会的?”

      这就不对了。我们声明的a是指针,sizeof a的结果一般是4,因为指针大小是4。这样无法达到初始化的结果。

      gjs:如果你不嫌麻烦,可以再写个宏,把原来的变量名找回来,然后……

      我还是不搞了。

      

  • 相关阅读:
    postgresql 在linux下导出数据
    第一次linux下安装nginx记录
    第一次搭建redis集群
    手动mvn install指令向maven本地仓库安装jar包
    windows10下Kafka环境搭建
    在win10环境下搭建 solr 开发环境
    git 常用命令
    生成文件夹的树结构信息
    List集合和JSON互转工具类
    Cmd命令 查看端口被占用
  • 原文地址:https://www.cnblogs.com/CsOH/p/5776532.html
Copyright © 2020-2023  润新知