将结构的实例分配给新的const结构实例

时间:2015-12-07 21:54:18

标签: c struct c99

我有一个公共函数,它对缓冲区执行读操作并执行摘要。它有一个const uint8_t *参数。

void do_digest(const uint8_t *buf, size_t size);

在内部,我将所有指针大小对包装在一个简单的缓冲区结构中:

typedef struct {
    uint8_t *buf;
    size_t size;
} myBuffer;

然而,作为一个迂腐的开发者,我想摆脱一个警告,指出在分配给myBuffer结构时参数的常量被剥离。

myBuffer foo = { buf, size };  // Warning: discards 'const' qualifier 

因此,最简单和最明确的解决方案是创建一个与const缓冲区一起使用的新结构类型:

typedef struct {
    const uint8_t *buf;
    size_t size;
} myConstBuffer;

myConstBuffer cfoo = { buf, size }; // No warnings, woohoo!

但是,有一个问题;在内部我传递指向这些缓冲区结构的指针。现在,如果我有一个可变的myBuffer实例并且我想将它传递给一个带有myConstBuffer指针的函数,我会收到一个抱怨不兼容类型的警告。

void some_internal_func(const myConstBuffer *b);

...

myBuffer mutable_buf = { ... };    
some_internal_func(&mutable_buf); // Warning: incompatible types.

似乎我正在为另一个警告交易。有更好的解决方案吗?

提前致谢。

2 个答案:

答案 0 :(得分:1)

回答你的问题:标准库中的函数经常会遇到这种情况,我不知道有什么更好的解决方案来构建参数,使其包含const限定符(即,如果你不要选择忽略警告:))

当函数在其原型中定义其参数之一具有类型<type> const *时,这并不是要求您提供类型const的参数,因为它表明函数不会尝试修改该地址的内容。函数通过指定const请求的是,在该函数调用期间,您(可能来自不同的线程)不会修改该地址的内容。

通常你会在库函数中看到这个,这些函数通常没有在C中实现。但是如果它们是,那么尝试修改<type> *const param指向的位置会导致编译器错误。

在我看来,方式更有可能发出与const相关的警告,而不是incompatible type,因为通过将变量强制转换为{{const更加安全。将它作为参数传递而不是传递给其他类型时。

答案 1 :(得分:0)

没有简单的解决方案,因为如果您使用const <type> *<type> *结构,则它们不兼容。

但是,如果您可以使用C11或至少C99,则可以自己buff structtypedef struct { size_t size; uint8_t data[]; } Buffer; ,其中包含大小和数据:

malloc

请注意,您无法从中创建静态或自动变量,因此您必须使用size_t buffer_length = 10; Buffer *buff = malloc(sizeof(*buff) + buffer_length); if ( buff != NULL ) { buff->size = buffer_length; ... &amp;朋友:

struct

buff可以像上面的const Buffer *一样传递到Buffer *struct,但您不再需要跟踪大小/长度,从而改变界面。

这称为灵活数组成员。它必须是sizeof(Buffer)的最后一个成员。 struct就好像数组有0个条目(在C中不允许,但是对于C99之前的代码是gcc扩展遗留。

更新:当然,只有在所有级别使用此struct时,这才有意义。因此,您只需将此{{1}}传递给使用此类数组加上长度/大小的所有函数。否则你将不得不复制数据,这通常是不需要的(没有例外的规则)。

在开发软件时,内部接口的设计通常需要很长一段时间的设计时间。但正如你现在看到的那样,值得付出努力。