Cast Between Incompatible Function Types in gcc

我们两清 提交于 2021-01-28 22:14:20

问题


I have a code generation script that was written by someone else around 2008 and has worked fine mostly unchanged since then. Just recently I tried compiling with gcc9 and I see 7300 warnings for "cast between incompatible function types" in the generated code.

The code takes a set of function pointers and various type identifiers and inserts everything into a big map that's used later for option serialization, printing, etc. Many functions and variables are cast and stored as some form of void *. The code otherwise compiles with no errors and works properly.

I tried various C-style casts, reinterpret_cast, and casting the function pointer to void(*)(void), but none of them remove the warnings. What's the correct way to cast the function to a generic type to avoid this warning? The only solution I can come up with is disabling -Wcast-function-type.

Here is one example line that generates warnings:

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);

The warning is related to these two functions:

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

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

Where filename_t is a class that interits from std::string.

Note that there are dozens of different str_from_***() functions that have different classes as arguments.

The warning I get is:

../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:


What's the correct way to cast the function to a generic type?

The answer is that there is no correct way. The warning is absolutely justified.

The point is that you have a typesafe function that you can pass only filename_t and you cast it to something that can take literally anything. The only way to not run into undefined bahavior is to still pass it a filename_t even though you now could pass anything else.

That yields the question of why you need to cast it to a generic type? You say that those functions get stored in a map with some type identifiers. Now, due to limited information it is hard to judge on this, but to me this sounds a little like artificially building a mechanism that choses the right function for you, while there is a perfectly working built in mechanism for this: function overload resolution.

So, at some point in the code you must have a filename_t object at hands. Then (I'm assuming) you infer some type identifier from it and use that to look up the proper function in a map. Then you pass your filename_t as a void* there, knowing that it will work.

I'm sure it's much more complex than this, but maybe you can identify this part of the logic and get rid of it: get rid of the map (at least that part that maps type identifiers to functions) and just call the function directly at a time where you still know the type (because then overload resolution will do the trick for you).

Templates can help you to keep the types instead of making everything void*.



来源:https://stackoverflow.com/questions/57014469/cast-between-incompatible-function-types-in-gcc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!