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

C 如何避免不必要的强制转换和涉及ptr到ptr到ptr的无关变量,c,pointers,C,Pointers,我有以下代码,完全工作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; struct

我有以下代码,完全工作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;
  }
structMSGB***init\u bstack(整块大小,整块大小)
{
structMSGB**Mp=calloc(黑色大小,黑色);
void*M=(void*)Mp+sizeof(structMSGB*)+sizeof(structMSGB*)*Blks\N;
structMSGB***startStack=(structMSGB***)Mp++;
对于(int i=0;iblk_size=Blk_size-sizeof(structMSGB)-sizeof(structMSGB*)-(i==0)*sizeof(structMSGB*);
Mp++;
}
*startStack=(structMSGB**)Mp;
返回startStack;
}
具体地说,是startStack变量让我恼火。我觉得应该有一种不用它的方法。返回值是ptr到ptr到struct的地址,也就是说,它需要将ptr返回到ptr到ptr到struct

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

**ptr变量

Blk_N长度的PTR表

大小为Blk_size-sizeof(ptr)的顺序块,但第一个块的大小(ptr)较小


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

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

请允许我向您介绍指针算法。给定一个
p
类型
some类型*
的指针和一个
x
整数值,表达式
p+x
相当于
(some类型*)((char*)p)+(x*sizeof(some类型))
。无论如何,这并不巧合,它也相当于
&p[x]
。也就是说,指针算法是根据指向对象的大小定义的

您提供的代码使用显式对象大小执行许多强制转换和算法,这些都可以通过依赖普通指针算法来消除

void *M = (void*) Mp + sizeof(structMSGB*) + sizeof(structMSGB*) * Blks_N;
……写得更好

structMSGB **M = Mp + 1 + Blks_N;
类似的情况也适用于代码中的其他地方

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

更新:


至于去掉变量
startStack
,看起来你可以用一些额外的算术来完成。你将它初始化为变量
Mp
的原始值。然后你将
Mp
的总次数增加为
Blks\N+1
次。在你只使用
startStack
的地方,它的值等于
Mp-(Blks_N+1)
。您可以使用该表达式而不是变量。不过,我当然不会做这样的更改。

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

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

structMSGB *xb=*(--*Mp); 
完成后,我可以使用以下命令返回块:

*((*Mp)++)=xb;
MBp还包含一个值,我以后可以使用它来释放内存-
free(MBp)

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


现在的问题是,代码可以进一步改进吗?当我真的不喜欢使用void*时,我正在使用void*进行铸造,但在这种情况下,我看不到任何替代方法。例如,如果我将
*Mp=(void*)(Mp+Blks\N+1);
替换为
*Mp=(Mp+Blks\N+1);
,它会工作,但gcc会抛出一个“来自不兼容指针类型的赋值”警告。除了使用(void*)还有更好的替代方法吗?

这是错误的
void*M=(void*)Mp+sizeof(structMSGB*)+sizeof(structMSGB*)*Blks;
你不能增加
void*
指针,你的意思是
void*M=(void*)((char*)Mp+sizeof(structMSGB*)+sizeof(structMSGB*)+sizeof(structMSGB*)*Blks)是的,你是对的,我应该用char而不是void,但无论如何它都可以正常工作。startStack变量和相关的强制转换确实让我感到困扰。启用编译器警告,它们应该可以帮助你解决类似的问题。为什么你要使用
***
指针,它们很少有用。这一切看起来都很正常这是错误的。如果它产生了预期的行为,那么这可能是因为依赖它的代码也是错误的,但是以一种补偿的方式。这肯定是错误的:
structMSGB***startStack=(structMSGB***)Mp++;
。实际上只有2个强制转换,我同意强制转换很糟糕,我很想摆脱它们。两者都涉及startStack变量,我希望不使用它。我主要使用sizeof作为sizeof(blahblah*)提醒我代码是如何工作的。它让我想起了我试图实现的内存区域结构。就像我说的,它工作得很好,但我会采纳你的建议,因为我目前正在尝试简化它。你之所以使用强制转换,主要是因为你在数据类型方面对编译器撒谎。考虑到你存储的是异构数据在您正在分配的内存中,一致返回类型的唯一可能性是指向适当的
结构
类型的指针,或者
void*
@poby,按照您的要求,用一种方法更新答案以去除变量
startStack
。不过,我建议您不要走这条路。您已经给了我这样的建议给我一些想法,让我想起
structMSGB *xb=*(--*Mp); 
*((*Mp)++)=xb;