我维护了一个非常古老的C项目(编写这些项目的程序员已经很久了)我找到了类似的东西:
(以//
开头的行给出包含以下行的文件的名称。)
// db/stor_procs/sp_table.c
/* Special hack prototype */
int32_t put_column_value(table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v);
// db/triggers/specials.c
/* BAD HACK */
int32_t put_column_value(table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v);
// db_sean_add_alarm/src/rt_access.c
int32_t put_column_value(struct xput_info *xptr, table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v);
// db_sean_add_alarm/stor_procs/sp_table.c
/* Special hack prototype */
int32_t put_column_value(table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v);
// db/src/rt_access.c
int32_t
put_column_value(struct xput_info *xptr, table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v){//....}
// db_sean_add_alarm/src/rt_access.c
int32_t
put_column_value(struct xput_info *xptr, table_t * tab, row_t * row, u_int16_t colnum, rt_value_t * v){//.....}
程序员从不在头文件中声明put_column_value
,但仅在.c文件中给出定义。更奇怪的是,我无法找到put_column_value
的任何定义,它将table_t *
作为第一个参数,我100%肯定{{1} }和table_t
是不同的类型(结构)。
但这不是整个故事。最奇怪的部分是我可以在其他.c文件中找到struct xput_info
的声明。现在我需要清理代码,但我无法理解如何处理这种C魔法。原始程序员在这里使用的“魔法”(hack)是什么?
整个项目有点大,我已经尽力简化问题了。请告诉我您是否需要其他任何信息来解决此问题。
修改
找出原因,这个项目链接到另一个库,并且该库有一个函数原型的定义,这就是为什么这个“魔术”(hack)可以找到实现。现在来解决一个大问题 - 这个项目没有坚实的单元测试,很难为它开发一个,没有测试我不能改变代码,不改变代码我不能做单元测试^ _ ^。啊,保持遗留代码总是不愉快的。
答案 0 :(得分:4)
这里有几件事需要担心。
答案 1 :(得分:3)
因此,您感到困惑的第一部分是声明和定义之间的不匹配。
对于构建过程,只要没有编译单元看到它们两者就没问题。但该计划在这个地方不起作用,是吗?
第二部分,关于将声明放入其他.c文件,是非常糟糕的风格。它应该 - 如果有的话 - 只在调试期间使用,我暂时需要另一个文件中的函数。
您可以通过将(正确的)声明放入您需要的头文件以及 - 以便检测不匹配 - 以及您声明它的位置来解决这两个问题。
答案 2 :(得分:3)
哎哟!我的猜测是,之前的程序员需要在一个地方向put_column_value
添加一个参数,但是在任何地方都懒得去做。他也有可能在实现的一半时间并且意图修复其他文件,但在作业完成之前退出。
您应该查看链接器命令,以查看哪个定义与程序实际链接。
您还应该检查是否从具有错误声明的文件中调用put_column_value
(在运行时)。由于额外的参数是第一个放置的,所以使用faulty声明的调用仍然可以工作,只要实现在这些实例中实际上不使用新参数(如果它写入它,它将破坏堆栈)。因此“魔术黑客”。它打破了C标准,在技术上导致了不确定的行为。
我的建议是,您要么在任何地方修复呼叫,要么将该功能吐成两部分,并重命名其中一部分。在任何一种情况下,您都应该将声明移回头文件。