Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird declaration and definition of a function in C

Tags:

c

I maintain a very old C project (the programmer who wrote these is already long gone) and I found something like this:

(Lines beginning with // give the name of the file that contains the following lines.)

Declarations:

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

Definitions:

// 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){//.....}

The programmer never declares put_column_value in a header file, but only gives the definition in the .c files. The more curious thing is that I can't find any definition of put_column_value that would take table_t * as the first parameter, and I'm 100% sure that table_t and struct xput_info are different types (structures).

But that's not the whole story. The weirdest part is that I can find declarations of put_column_value in other .c files. Now I need to clean up the code, but I cannot understand how to deal with this kind of C magic. What is the "magic" (hack) the original programmer used here?

The whole project is kind of big, and I've already tried my best to simplify the problem. Please tell me if there's any additional information you need to solve this problem.

Edit

Find out why, this project link to the other library, and that library has a definition of the function prototype, that is why this "magic"(hack) can find the implementation. Now come a big problem to solve--this project do not have solid unit test and hard to develop one for it, without testing I cannot change the codes, without changing the codes I cannot do unit test ^_^. Ahhh, maintain legacy codes always is not a pleasant task.

like image 481
user3689849 Avatar asked Aug 22 '14 07:08

user3689849


People also ask

What is declaration and definition of function in C?

A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function. The C standard library provides numerous built-in functions that your program can call.

What is the difference between a declaration and a definition of a function?

Function declaration is a prototype that specifies the function name, return types and parameters without the function body. Function Definition, on the other hand, refers to the actual function that specifies the function name, return types and parameters with the function body.

What is declaration and definition in C with example?

i.e., declaration gives details about the properties of a variable. Whereas, Definition of a variable says where the variable gets stored. i.e., memory for the variable is allocated during the definition of the variable. In C language definition and declaration for a variable takes place at the same time.

What is the declaration of a function?

A function declaration introduces an identifier that designates a function and, optionally, specifies the types of the function parameters (the prototype). Function declarations (unlike definitions) may appear at block scope as well as file scope.


3 Answers

You have several things to worry about here.

  1. The appalling programming style that puts prototypes in source code rather than header files. This is easy(but tedious) to fix.
  2. The mismatch between the declarations and the definitions. Given that you have a different number of parameters in the prototype and the two definitions of the function. It seems likely that these prototypes aren't actually used, because if they were the program would crash (assuming that is that the actual code doesn't do something truly disgusting with its arguments). So you may have the opportunity to do some cleanup.
  3. You have two implementations of put_column_value. Presumably these are in what is intended to be in different libraries that should never be used together. It looks like one of these directories contains a new version of the library with some sort of alarm but I'm just guessing from the name.
like image 159
Tom Tanner Avatar answered Oct 04 '22 03:10

Tom Tanner


So the first part you are confused about is the mismatch between declarations and definitions.

For the build process, that's ok as long as no compilation unit sees them both. But the program doesn't work at this place, does it?

The second part, which is about putting declarations into other .c files, is very bad style. It should - if at all - only be used during debugging where I temporarily need a function in another file.

You can fix both by putting the (correct) declaration into a header file which you include from where you need it as well as - in order to detect mismatches - from where you declare it.

like image 26
glglgl Avatar answered Oct 04 '22 03:10

glglgl


OUCH! My guess is that the prior programmer needed to add a parameter to put_column_value in one place, but was too lazy to do it everywhere. It is also possible that he was halfway through the implementation and meant to fix the other files, but then quit before the job was finished.

You should look at the linker command(s) to see which definition is actually linked with the program(s).

You should also check to see if put_column_value is ever called (at runtime) from the files that have the faulty declaration. Since the extra parameter is placed first, calls using the faulty declaration could still work as long as the implementation doesn't actually use the new parameter in those instances (if it writes to it, it will corrupt the stack). Hence "Magic hack". It breaks the C standard and technically results in undefined behaviour.

My advice is that you either fix the call everywhere or that you spit the function into two, and rename one of them. In either case, you should move the declaration(s) back to the header file.

like image 25
Klas Lindbäck Avatar answered Oct 04 '22 03:10

Klas Lindbäck