Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C/C++ linkage convention

Tags:

c++

c

declspec

When calling C++ algorithms like copy_if, transform etc which take a unary or binary function as the last argument, can I pass a C library function like atoi or tolower.

For e.g. below calls work fine and give the correct output (tried in ideone)

1) transform (foo, foo+5, bar, atoi);
2) transform (foo, foo+5, bar, ptr_fun(atoi));
3) transform(s.begin(),s.end(),s.begin(), static_cast<int (*)(int)>(tolower));

Is this usage guaranteed to work with all C++ compilers ?

The book thinking in C++ mentions "This works with some compilers, but it is not required to." The reason mentioned is (as I understand it) transform is C++ function and expects its last argument to have same calling convention.

The book also suggests a solution for this problem which is to create a wrapper function like this in a separate cpp file and do not include iostreams header file.

// tolower_wrapper.cpp
string strTolower(string s) {
  transform(s.begin(), s.end(), s.begin(), tolower);
  return s;
} 

This works fine, but I did not understand how this resolves the calling convention issue ? transform is still a c++ function and tolower is still a C function in the strTolower, so how this different calling conventions are handled here.

like image 578
irappa Avatar asked Mar 18 '14 00:03

irappa


1 Answers

The first thing to note, which is not actually part of your question but which might help explain for someone reading this, is that the algorithms can take either a function pointer or a function object as an argument.

A function pointer is just that - a pointer to a function which expects to take a specific set of parameters and return a specific type.

A function object is an instance of a class which has overridden operator().

When expanding the algorithm template, the compiler will be able to see which of the two cases applies and will generate appropriate calling code.

In the case of a C function being used as a binary function in an algorithm, it is a function pointer that you are supplying. You can call a C function from C++, as long as it is declared extern C { ... }.

Many compilers come with header files for the C library functions which include something like this:

#ifdef  __cplusplus
extern "C" {
#endif

/* function declarations here */

#ifdef  __cplusplus
}
#endif

so that if you include a C library header from a C++ program, the contained functions will all be magically available to you. That part, however, is not guaranteed by the standard, which is why your book states it may not work with all compilers.

Another wrinkle is that you are not allowed to cast function pointers to a type with a different language linkage, which in at least some of your examples you are doing, although some compilers do seem to allow that anyway - for example see this GCC Bug.

The other catch, which applies specifically to tolower for example, is that some of the names of C library functions are also names of functions or templates in the C++ std library. For example, the name tolower is also defined in <locale>. This specific case is discussed in this GCC bug report. The use of a wrapper, compiled in a separate compilation unit which does not include the conflicting declarations, would resolve this issue.

like image 164
harmic Avatar answered Sep 19 '22 18:09

harmic