用宏实现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:如果你不嫌麻烦,可以再写个宏,把原来的变量名找回来,然后……

我还是不搞了。

原文链接: https://www.cnblogs.com/CsOH/p/5776532.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/238832

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 下午5:58
下一篇 2023年2月13日 下午5:58

相关推荐