我有以下typedef
及更高阶函数:
typedef void block_fn (struct block*, block_sector_t, void* buffer);
static void block_apply (struct page* page, block_fn *block_fn) {
int i = 0;
for (i = 0; i < PAGE_SECTORS; i++) {
block_fn(swap.device, page->sector * PAGE_SECTORS + i, page_kpage(page)
+ i * BLOCK_SECTOR_SIZE);
}
}
我在以下两个地方称呼它:
block_apply (page, &block_write);
...
block_apply (page, &block_read);
block_read
和block_write
具有以下签名:
void block_read (struct block *, block_sector_t, void *);
void block_write (struct block *, block_sector_t, const void *);
这导致海湾合作委员会抱怨:
../../ vm / swap.c:94:13:注意:预期
void (*)(struct block *, block_sector_t, void *)
但参数类型为void (*)(struct block *, block_sector_t, const void *)
海湾合作委员会是否有权生气?以这种方式传递此函数指针是否安全?
编辑:据我所知,这两个函数指针的类型不同。我的问题是它是否安全以这种方式使用它们:它能触发未定义的行为吗?是否存在以这种方式传递具有不兼容类型的函数指针会导致意外情况发生的情况?答案 0 :(得分:3)
是的,一般来说抱怨是正确的,但在你的情况下没有意义
通过说const void *,你声明该函数不会修改 指向数据。通过省略const,你可以说它可能。
函数签名是调用者和被调用者之间的契约,即编译器 强制执行。编译器阻止代码发布比它更严格的签名 实现(例如,在写入它们时发布只读参数。)
但是,在您的情况下,您只需要指向具有有限类型检查功能的指针。
您可以将类型声明为使用const void *,并使用类型转换覆盖const 当你调用它时。
答案 1 :(得分:0)
两种指针类型不兼容。
IMO,以这种方式传递此函数指针是不安全的。
更高级别的代码知道block_apply()
因其功能签名而可以处理的类型。要将不同的类型传递给block_apply()
,需要做两件事:1)更高级别的代码击败签名(强制转换)和2)更高级别的代码知道可以这样做。
最好不要强迫更高级别的代码投射,并减轻了解block_apply()
内部运作的负担。
为了避免强制转换,代码可以创建另一个函数block_apply_const()
。然后根据需要致电block_apply(page, &block_read)
和block_apply_const(&block_write)
。
typedef void block_fn_const (struct block*, block_sector_t, const void* buffer);
static void block_apply_const (struct page* page, block_fn_const *block_fn) {
// same code
}
但是重复代码。
或者,包装函数可以执行转换。这比使用强制调用block_apply()
调用更高级代码更好。由于应该谨慎进行转换,并且这些static
函数知道可以执行转换,这里的代码可以执行此操作。
static void block_apply_const (struct page* page, block_fn_const *block_fn) {
block_apply(page, (block_fn) block_fn);
}