6

In C++, there are two versions of qsort() provided by the standard library:

extern "C" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
extern "C++" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));

bsearch() is about the same.

My question is, how does overload resolution work when calling qsort()? Does it automatically link to the appropriate function based on the linkage type ("C" or "C++") of the function pointer passed as the last argument? Or the caller needs to specify explicitly with some sort of extra syntax?

(Let's just put away the temptation to call std::sort for a second...)

alk
  • 69,737
  • 10
  • 105
  • 255
goodbyeera
  • 3,169
  • 2
  • 18
  • 39
  • I never see extern "C++", extern "C" ask to c++ compiler to use C mangling. Where did you see extern "C++" void qsort.... – mpromonet Feb 22 '14 at 14:02
  • 1
    @mpromonet: The C++ standard. – goodbyeera Feb 22 '14 at 14:04
  • I don't understand your question, however perhaps running nm on your executable (or library) will answer to your question ? – mpromonet Feb 22 '14 at 14:12
  • @mpromonet The question is perfectly clear to me. Running nm won't help in any way whatsoever when dealing with an implementation that doesn't implement this aspect of C++ the way the standard specifies. –  Feb 22 '14 at 14:14

1 Answers1

3

The int (*compar)(const void*, const void*) parameter has different types for the two different overloads. For the first overload, it's an extern "C" function pointer parameter. For the second overload, it's an extern "C++" function pointer parameter. Any function pointer you pass to qsort will already have some sort of linkage, and that is what gets used to determine which overload to call.

To quote the standard:

7.5 Linkage specifications [dcl.link]

All function types, function names with external linkage, and variable names with external linkage have a language linkage. [...] The default language linkage of all function types, function names, and variable names is C++ language linkage. Two function types with different language linkages are distinct types even if they are otherwise identical.

In fact, I don't think the standard actually means to require that the two qsort overloads really do have different linkage. Unlike in C, user-provided declarations of standard library functions are not allowed; the relevant difference between them is the type of compar. They could have been declared as

extern "C" typedef int (*__compar_fnp_c)(const void *, const void *);
extern "C++" typedef int (*__compar_fnp_cxx)(const void *, const void *);
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_c compar);
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_cxx compar);

where it should be more obvious that __compar_fnp_c and __compar_fnp_cxx are different types. That said, the as-if rule doesn't allow this implementation, since it would break code that takes a pointer or reference to qsort.

Note that GCC, as well as some other compilers, don't implement this correctly, and don't treat linkage as part of the function pointer's type. On such implementations, only one version of qsort will have been made available, to prevent a conflict during overload resolution.

Community
  • 1
  • 1
  • I'm not so sure whether the linkage of a function pointer is part of its type signature. Say, I don't know how to specify the linkage in a function pointer declaration. Mimicking the typedef syntax you used, I got compile error for a declaration like `extern "C" int (*p)(int);` in both g++ and clang++. – goodbyeera Feb 22 '14 at 14:19
  • @goodbyeera That exact line you're using there is accepted by both g++ and clang++ on my system, versions 4.8.2 and 3.4 respectively. (Edit) If you're trying this for a local variable declaration, then you're right, the syntax doesn't allow this. The syntax doesn't allow any way to specify the type of function pointer, for a block-scope declaration or definition. You'd need to use a file-scope typedef instead, and use that typedef in your local variable. –  Feb 22 '14 at 14:22
  • @goodbyeera I edited my comment to address that at pretty much the same time that you posted your new comment :) –  Feb 22 '14 at 14:25
  • Thank you very much for finding the relevant part of the standard. That's pretty clear. It seems a separate question whether compilers pay respect to that. I tried declaring functions taking function pointer parameter which differs only in its linkage, and both g++ and clang++ reported function redefinition. (Of course it's possible that we are not declaring the linkage in a correct way with the typedef magic as you presented.) – goodbyeera Feb 22 '14 at 15:01
  • 1
    @goodbyeera I'm guessing you probably are doing that correctly. Both GCC and clang have open bugs ([GCC PR 2316](http://gcc.gnu.org/PR2316), [clang bug 15563](http://llvm.org/bugs/show_bug.cgi?id=15563)) about exactly this issue. For GCC [a two-year-old proof-of-concept patch](http://gcc.gnu.org/bugzilla/attachment.cgi?id=26237) is available that you could experiment with, if you feel like it. –  Feb 22 '14 at 15:12