C 如何避免不必要的强制转换和涉及ptr到ptr到ptr的无关变量
我有以下代码,完全工作100%良好,没有错误,编译或运行时。但它非常丑陋,因为我必须强制转换并使用一个无关变量,而我确信有一种方法可以不使用任何一个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
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;