在gcc

时间:2019-07-12 21:59:31

标签: c++ function-pointers

我有一个代码生成脚本,该脚本是在2008年左右由其他人编写的,此后几乎没有发生任何变化。就在最近,我尝试使用gcc9进行编译,并且在生成的代码中看到7300警告“在不兼容的函数类型之间进行转换”。

该代码采用一组函数指针和各种类型标识符,并将所有内容插入到大映射中,稍后用于选项序列化,打印等。许多函数和变量都以void *的形式进行转换和存储。否则,该代码可以正确编译,并且不会出错。

我尝试了各种C风格的强制转换,reinterpret_cast和将函数指针强制转换为void(*)(void),但是它们都没有删除警告。为避免此警告,将函数强制转换为通用类型的正确方法是什么?我唯一能想到的解决方案是禁用-Wcast-function-type。

以下是生成警告的示例行:

pim.must_find("input_fn")->set_introspect_info( sizeof(filename_t), ((char *)(&p_cn->input_fn)) - ((char *)p_cn), 0,invalid_offset, (str_from_base_t *)str_from_filename_t, (send_base_t *)send_filename_t, (recv_base_t *)recv_filename_t, (val_from_param_t *)val_from_param_filename_t, 0);

警告与以下两个功能有关:

typedef std::string str_from_base_t( void const * );

std::string str_from_filename_t( filename_t const & v ) { return v; }

filename_t是从std :: string插入的类。

请注意,有数十种不同的str_from _ ***()函数具有不同的类作为参数。

我得到的警告是:

../src/gen/DEFReader_PostParam.cc: In function 'void croix::DEFReaderCLI_introspect_pim_init()':
../src/gen/DEFReader_PostParam.cc:25:153: warning: cast between incompatible function types from 'std::string (*)(const croix::filename_t&)' {aka 'std::basic_string<char> (*)(const croix::filename_t&)'} to 'std::string (*)(const void*)' {aka 'std::basic_string<char> (*)(const void*)'} [-Wcast-function-type]
25 |  pim.must_find("input_fn")->set_introspect_info( sizeof(filename_t), ((char *)(&p_cn->input_fn)) - ((char *)p_cn), 0,invalid_offset, (str_from_base_t *)str_from_filename_t, (send_base_t *)send_filename_t, (recv_base_t *)recv_filename_t, (val_from_param_t *)val_from_param_filename_t, 0);

1 个答案:

答案 0 :(得分:1)

  

将函数转换为泛型的正确方法是什么?

答案是没有正确的方法。该警告是完全合理的。

重点是您拥有一个类型安全函数,该函数只能传递filename_t并将其强制转换为可以实际使用任何东西的东西。即使您现在可以传递其他任何内容,唯一不会陷入不确定行为的唯一方法就是仍然将其传递给filename_t

这产生了一个问题,为什么您需要将其强制转换为泛型?您说这些函数被存储在带有某些类型标识符的映射中。现在,由于信息有限,很难对此进行判断,但是对我来说,这听起来有点像人为地建立一种机制为您选择正确的功能,而为此目的有一个完善的内置机制:函数重载解析。

因此,在代码中的某些点上,您必须有一个filename_t对象。然后(我假设)您从中推断出一些类型标识符,并使用该类型标识符在映射中查找适当的函数。然后,您将filename_t作为void*传递到那里,知道它将起作用。

我敢肯定它比这要复杂得多,但是也许您可以识别出逻辑的这一部分并摆脱它:摆脱地图(至少将类型标识符映射到函数的那一部分),然后调用在您仍然知道类型的时候直接使用该函数(因为重载解析将为您解决问题)。

模板可以帮助您保留类型,而不用制作void*