转换旧的 C 代码

Converting old C code

我在项目源代码中有这个代码片段,我正在处理

void func(void **p,size_t s)
{
    *p = malloc(s+sizeof(size_t));
    *(((size_t *)(*p))++) = s;
}

gcc-4.7 不编译它。海合会 returns

lvalue required as increment operand 

错误信息。我改成了

stp = ((size_t *)(*p));
*(stp ++) = s;

stp = ((size_t *)(*p));
*stp = *stp + 1;
*stp = s;

gcc 编译它们。但应用程序无法正常工作。 转换是真的吗?有什么转换工具吗?

*(((size_t *)(*p))++) = s;

Breakdown:
*(
  (
    (size_t *) (*p)
  ) ++
) = s

的意思是:将 *p 作为指向 size_t 的指针(之后我们称其为 ptr),取消引用它(= 在地址 *p),将该值赋给 s,最后递增 ptr(也就是说,将 *p 中的地址递增 sizeof(size_t)

您可以将其翻译成:

size_t *ptr = (size_t*)(*p); //second pair of paren is optionnal
s = *ptr;
ptr = ptr + 1; //Warning: This will only modify the variable ptr and not
               //the data at its original place *p, if the remainder of
               //the program is based on that (which I highly suspect)
               //you should do instead :

(size_t*)*p = (size_t*)(*p) + 1; //This also ensures "+1" is treated as
                                 //"add the sizeof(size_t)" because *p
                                 //points to a size_t typed variable

您也可以重新键入一个变量并让它指向与 p 相同的位置并完成强制转换:

void func(void **p,size_t s)
{
  size_t **ptr = p;
  *ptr = malloc(s+sizeof(size_t));

  if (*ptr == NULL) etc...

  *((*ptr)++) = s;
}

这个想法似乎是分配一定数量的内存(s额外的数量来存储分配在与前导相同区域中的这个大小块,然后 return 指向存储大小后面的指针。

所以试试这个:

void func(void ** p, size_t s)
{
  size_t * sp = malloc(s + sizeof s);
  if (NULL != sp)
  {
    *sp = s;
    ++sp;
  }

  *p = sp;
}

顺便说一句,释放分配的内存并不简单。

一个典型的调用序列,也释放了这个函数 returns,然后看起来像这样:

void * pv = NULL;
func(&pv, 42);
if (NULL != pv)
{
  /* Use 42 bytes of memory pointed to by pv here. */

  free(((char *) pv) - sizeof (size_t));
}
  • func2() :添加变量可以提高可读性,恕我直言。 (然后内联将摆脱它)
  • 第二个函数func3()演示了使用return值而不是通过引用传递一个(opaque)指针可以避免复杂性和转换

#include <stdio.h>
#include <stdlib.h>

void func2(void **p,size_t s)
{
    size_t **pp;
    pp = (size_t **) p; // only one cast
    *pp = malloc(s+sizeof(size_t));
    if (!*pp) return;
                          fprintf(stderr,"[mallocd %p]", *pp);
    *pp[0] = s;
    *pp += 1;
}

void *func3(size_t s)
{
    size_t *p;
    p = malloc(s+sizeof *p);
    if (!p) return NULL;
                          fprintf(stderr,"[mallocd %p]", p);
    p[0] = s;
    return p+1;
}

int main(void)
{
char *p = NULL , *p2 = NULL;

func2( (void**) &p, 666);       // yet another cast
fprintf(stderr,"returned p := %p\n", p);

p2 = func3( 666); // No cast!!!
fprintf(stderr,"returned p2 := %p\n", p2);

return 0;
}

尝试

void func(void **p,size_t s)
{
    *p = malloc(s+sizeof(size_t));
    *(*(size_t **)p)++ = s;
}

这是分配 s 字节的内存,加上足够的额外空间来容纳 s,在 space 的开头存储 s 并修改 *p 指向之后。

更明智和更清晰(并避免转换!)将是:

void *func(size_t s)
{
    size_t *p = malloc(s + sizeof(size_t));
    if (p) *p++ = s;
    return p;
}

但这需要更改调用此函数的代码以获取 return 值并将其存储在需要的任何位置,而不是将额外的指针作为参数传递:

some_ptr = func(needed_size);

而不是

func((void **)&some_ptr, needed_size);

也避免强制转换...