c-如何避免不必要的强制转换和涉及ptr-ptr-ptr的无关变量



我有以下代码,无论是编译还是运行时,都能100%正常工作,没有错误。但它非常丑陋,因为当我确信有办法不使用无关变量时,我必须强制转换和使用无关变量。

structMSGB ***init_bstack(int Blk_Size,int Blks_N)
{
structMSGB **Mp=calloc(Blk_Size,Blks_N);
void *M=(void*)Mp+sizeof(structMSGB*)+sizeof(structMSGB*)*Blks_N;
structMSGB ***startStack=(structMSGB***)Mp++;
for(int i=0;i<Blks_N;i++)
{
*Mp=M+(Blk_Size-sizeof(structMSGB*))*i-(i==1)*sizeof(structMSGB*);
(*Mp)->blk_size=Blk_Size-sizeof(structMSGB)-sizeof(structMSGB*)-(i==0)*sizeof(structMSGB*);
Mp++;
}
*startStack=(structMSGB **)Mp;
return startStack;
}

具体来说,startStack变量让我很恼火。我觉得应该有一种方法完全不用它。返回值是一个ptr到一个结构的ptr的地址,即它需要返回一个ptr-to-ptr-to-struct。

返回的结果是大小为Blk_Size字节的内存块的起始地址,按顺序由以下部分组成:

**ptr变量

Blk_N长度的ptr表

大小为Blk_size-sizeof(ptr)的顺序块,但sizeof(pt r)较小的第一个块除外。

这样做是为了确保整个内存分配都得到使用,不多也不少。

当代码对类型为void *的表达式执行算术运算时,它会调用未定义的行为。有些编译器会将其视为void *就是char *,如果您的代码确实有效,那么这就是发生的事情,但仍然是错误的。而且可能没有必要,启动。

请允许我向您介绍指针算术。给定类型为some_type *的指针p和整数值x,表达式p + x等效于(some_type *) (((char *) p) + (x * sizeof(some_type))。无论如何,这也相当于&p[x]。也就是说,指针算术是根据被指向对象的大小来定义的。

您所展示的代码使用显式对象大小执行了大量的强制转换和算术运算,这些对象大小可以通过依赖普通指针算术来消除。例如,这个。。。

void *M = (void*) Mp + sizeof(structMSGB*) + sizeof(structMSGB*) * Blks_N;

写会更好

structMSGB **M = Mp + 1 + Blks_N;

类似的情况也适用于代码中的其他地方。

一般来说,好的代码除了用于内存分配之外,很少需要sizeof,并且只需要很少的强制转换。每当你发现自己在写演员阵容时,你都应该问问自己为什么,并确保你有一个好的答案。

更新:

至于去掉变量startStack,看起来可以以一些额外的算术为代价。将其初始化为变量Mp的原始值。然后以Blks_N + 1的总和递增Mp。在仅使用startStack的点上,其值等于Mp - (Blks_N + 1)。您可以使用该表达式而不是变量。我当然不会做出这样的改变。

这是一个大大改进的版本,它解决了我的问题(在@John Bollinger的帮助下):

void *init_bstack(int Blk_Size,int Blks_N)
{
structMSGB **Mp=calloc(Blk_Size,Blks_N);
Mp[0]=Mp[1]=(void*)&Mp[Blks_N+1];
Mp[1]->blk_size=Blk_Size-sizeof(structMSGB)-sizeof(structMSGB*)sizeof(structMSGB*);
for(int i=1;i<Blks_N;i++)
{
Mp[i+1]=Blk_Size+(void*)Mp[i]-8-(i==1)*8;
Mp[i+1]->blk_size=Blk_Size-sizeof(structMSGB)-sizeof(structMSGB*);
}
return Mp;
}

我这样使用返回值:

structMSGB ***MBp=init_bstack(4096,10);

然后我可以使用*MBp来分配内存块,使用:

structMSGB *xb=*(--*Mp); 

当我完成后,我可以返回块:

*((*Mp)++)=xb;

MBp还包含一个我以后可以用来释放内存的值——free(MBp)

我认为MBp需要是***类型,因为它包含calloc’d块的地址,其中的前8个字节包含一个ptr到ptr表中。该地址被传递以分配和释放函数,因此该地址处的ptr可以相应地递增或递减,并且还提供所请求的内存块。

现在的问题是,代码是否可以进一步改进?当我真的不喜欢选角的时候,我会带着一种空虚感选角,但在这种情况下,我看不到任何其他选择。例如,如果我用*Mp=(Mp+Blks_N+1);替换*Mp=(void*)(Mp+Blks_N+1);,它可以工作,但gcc会弹出"不兼容指针类型的赋值"警告。有没有比使用(void*)更好的选择?

相关内容

最新更新