I know that C++ doesn't specify the order in which parameters are passed to a function. But if we write the following code:
void __cdecl func(int a, int b, int c)
{
printf("%d,%d,%d", a,b,c);
}
int main()
{
int i=10;
func(++i, i, ++i);
}
Can we reliably say the output would be 12,11,11 since the __cdecl ensures that argument-passing order is right to left?
As per the Standard, there are two things you need to understand and differentiate:
C++ doesn't specify the order in which parameters are passed to a
function (as you said yourself, that is true!)
C++ doesn't specify the order in which the function arguments are evaluated [expr.call].
Now, please note, __cdecl ensures only the first, not the second. Calling conventions decide only how the functions arguments will be passed, left-to-right or right-to-left; they can still be evaluated in ANY order!
Hope this clarifies your doubts regarding the calling conventions.
However, since these conventions are Microsoft compiler extension to C++, so your code is non-portable. In that case, you can see how MSVC++ compiler evaluates function arguments and be relax IF you don't want to run the same code on other platform!
func(++i, i, ++i);
Note that this particular code invokes undefined behavior, because i is incremented more than once without any intervening any sequence point.
No, you cannot assume that.
An optimizing compiler will inline short functions. All that __stdcall will garantee is that the __stdcall version of function will be generated, but this does not mean that compiler cannot also inline it in the same time.
If you really want to be sure it's not inlined, you have to declare it in another compilation unit, alough linker optimizations could inline even in this case.
Also, the order of parameters on the stack have nothing to do with the order they are evaluated. For example, for a function call fn(a, b, c) GCC usually won't do
push c
push b
push a
call fn
but rather
sub esp, 0xC
mov [esp+8], c
mov [esp+4], b
mov [esp], a
call fn
Note that in the second case it has no restrictions on the order.
It is possible for a particular C implementation to define what a compiler will do in certain cases which would, per the standard, be "undefined behavior". For example, setting an int variable to ~0U would constitute undefined behavior, but there's nothing in the C standard that wouldn't allow a compiler to evaluate the int as -1 (or -493, for that matter). Nor is there anything that would forbid a particular compiler vendor from stating that their particular compiler will in fact set the variable to -1. Since __cdecl isn't defined in the C standard, and is only applicable to certain compilers, the question of how its semantics are defined is up to those vendors; since the C standard lists it as undocumented behavior, it will only be documented to the extent particular vendors document it.
You are changing the same variable more than once between sequence points (function argument evaluation is one sequence point), which cause undefined behaviour regardless of calling convention.
Related
In some circumstances, we use tags to discriminate between functions. A tag is usually an empty struct:
struct Tag { };
Suppose that I have a function, which uses this tag:
void func(Tag, int a);
Now, let's call this function:
func(Tag(), 42);
And check out the resulting x86-64 disassembly, godbolt:
mov edi, 42
jmp func(Tag, int) # TAILCALL
It is fine, the tag gets completely optimized away: there is no register/stack space allocated for it.
But, if I check out other platforms, the tag has some presence.
On ARM, r0 is used as the tag, and it gets zeroed (seems unnecessary):
mov r1, #42
mov r0, #0
b func(Tag, int)
With MSVC,ecx is used as the tag, and it is "initialized" from the stack (again, seems unnecessary):
movzx ecx, BYTE PTR $T1[rsp]
mov edx, 42 ; 0000002aH
jmp void func(Tag,int) ; func
My question is: is there a tag technique, which is equally optimized on all these platforms?
Note: I don't find where the SysV ABI specifies that empty classes can be optimized away at parameter passing... (and even, the Itanium C++ ABI says: "Empty classes will be passed no differently from ordinary classes".)
I think the basic problem here is that when generating the standalone version of a function, the compiler has to generate code that can be called by anyone from anywhere according to the respective calling convention. And when generating a call to a function without knowing its definition, all the compiler really knows is that this function expects to be called according to the calling convention. Based on that, it would seem that, unless the calling convention specifies that function parameters of empty type are removed, the compiler can't really optimize away parameters from function calls in general. Now, it may be technically legal for a C++ compiler to make up whatever calling convention it sees fit for a given function signature on the spot unless the function has non-C++ language linkage (e.g., an extern "C" function). But in practice, this would most likely not be all that simple. First of all, you then need an algorithm that can decide what the best calling convention for a given function signature looks like in general. And second, the ability to link code that was not necessarily all generated with exactly the same version of exactly the same compiler using exactly the same flags, while not required by the C++ standard, is probably relevant in practice. Function calling convention optimization is certainly not impossible. But I'm not aware of any C++ compiler that actually does it (when generating object code).
One possible solution would be to, e.g., use different names for the actual function implementations and have simple inline wrapper functions that translate calls with Tag types to the respective implementations:
struct TagA { };
struct TagB { };
inline void func(int a, TagA)
{
void funcA(int a);
funcA(a);
}
inline void func(int a, TagB)
{
void funcB(int a);
funcB(a);
}
void call() {
func(42, TagA());
func(42, TagB());
}
try it out here
Also, note that, while the compiler may generate the function calls like that in the initial object files, link-time optimizations may be able to get rid of unused parameters in the end. At least one major compiler even documents such behavior…
In C++, it is a compiler error to call a function before it is declared. But in C, it may compile.
#include<stdio.h>
int main()
{
foo(); // foo() is called before its declaration/definition
}
int foo()
{
printf("Hello");
return 0;
}
I have tried and know that it is correct but I can't get the reason behind it. Can anyone please explain how the compilation process actually takes place and differs in both the languages.
The fact that the code "compiles" as a c program doesn't mean you can do it. The compiler should warn about implicit declaration of the function foo().
In this particular case implicit declaration would declare an identical foo() and nothing bad will happen.
But suppose the following, say this is
main.c
/* Don't include any header, why would you include it if you don't
need prototypes? */
int main(void)
{
printf("%d\n", foo()); // Use "%d" because the compiler will
// implicitly declare `foo()` as
//
// int foo()
//
// Using the "correct" specifier, would
// invoke undefined behavior "too".
return 0;
}
Now suppose foo() was defined in a different compilation unit1 foo.c as
foo.c
double foo()
{
return 3.5;
}
does it work as expected?
You could imagine what would happen if you use malloc() without including stdio.h, which is pretty much the same situation I try to explain above.
So doing this will invoke undefined behavior2, thus the term "Works" is not applicable in the understandable sense in this situation.
The reason this could compile is because in the very old days it was allowed by the c standard, namely the c89 standard.
The c++ standard has never allowed this so you can't compile a c++ program if you call a function that has no prototype ("declaration") in the code before it's called.
Modern c compilers warn about this because of the potential for undefined behavior that can easily occur, and since it's not that hard to forget to add a prototype or to include the appropriate header it's better for the programmer if the compiler can warn about this instead of suddenly having a very unexplicable bug.
1It can't be compiled in the same file because it would be defined with a different return type, since it was already implicitly declared
2Starting with the fact that double and int are different types, there will be undefined behavior because of this.
When C was developed, the function name was all you needed to be able to call it. Matching arguments to function parameters was strictly the business of the programmer; the compiler didn't care if you passed three floats to something that needed just an integer.
However, that turned out to be rather error prone, so later iterations of the C language added function prototypes as a (still optional) additional restriction. In C++ these restrictions have been tightened further: now a function prototype is always mandatory.
We can speculate on why, but in part this is because in C++ it is no longer enough to simply know the function name. There can be multiple functions with the same name, but with different arguments, and the compiler must figure out which one to call. It also has to figure out how to call (direct or virtual?), and it may even have to generate code in case of a template function.
In light of all that I think it makes sense to have the language demand that the function prototype be known at the point where the function is called.
Originally, C had no function prototypes, and C++ did not exist.
If you said
extern double atof();
this said that atof was a function returning double. (Nothing was said about its arguments.)
If you then said
double d = atof("1.3");
it would work. If you said
double d2 = atof(); /* whoops, forgot the argument to atof() */
the compiler would not complain, but something weird would happen if you tried to run it.
In those days, if you wanted to catch errors related to calling functions with the wrong number or type of arguments, that was the job of a separate program, lint, not the C compiler.
Also in those days, if you just called a function out of the blue that the compiler had never heard of before, like this:
int i = atoi("42");
the compiler basically pretended that earlier you had said
extern int atoi();
This was what was called an implicit function declaration. Whenever the compiler saw a call to a function whose name it didn't know, the compiler assumed it was a function returning int.
Fast forward a few years. C++ invents the function prototypes that we know today. Among other things, they let you declare the number and types of the arguments expected by a function, not just its return type.
Fast forward a few more years, C adopts function prototypes, optionally. You can use them if you want, but if you don't, the compiler will still do an implicit declaration on any unknown function call it sees.
Fast forward a few more years, to C11. Now implicit int is finally gone. A compiler is required to complain if you call a function without declaring it first.
But even today, you may be using a pre-C11 compiler that's still happy with implicit int. And a C11-complaint compiler may choose to issue a mere warning (not a compilation-killing error) if you forget to declare a function before calling it. And a C11-compliant compiler may offer an option to turn off those warnings, and quietly accept implicit ints. (For example, when I use the very modern clang, I arrange to invoke it with -Wno-implicit-int, meaning that I don't want warnings about implicit int, because I've still got lots of old, working code that I don't feel like rewriting.)
Why can I call a function in C without declaring it?
Because in C, but not in C++, a function without a prototype is assumed to return an int. This is an implicit declaration of that function. If that assumption turns out to be true (the function is declared later on with return-type of int), then the program compiles just fine.
If that assumption turns out to be false (it was assumed to return an int, but then actually is found to return a double, for example) then you get a compiler error that two functions cannot have the same name. (eg. int foo() and double foo() cannot both exist in the same program)
Note that all of this is C only.In C++, implicit declarations are not allowed. Even if they were, the error message would be different because C++ has function overloading. The error would say that overloads of a function cannot differ only by return type. (overloading happens in the parameter list, not the return-type)
main()
{
f();
}
int f( int i, float fl)
{
printf("function");
}
Why does the above code runs successfully in 'C' and prints function when it should report an error, as f () is being called before it is declared.
When it's running successfully in 'C', then why not in 'C++'. When running in c++ it's showing: error: 'f' was not declared in this scope
If it is because of something like the compiler assumes an undeclared function to return an int and accept an unspecified number of arguments, then why does it runs successfully for the function below too ( i.e. when returning the returning type to void instead of int ?
void f ( int i, float fl)
{
printf("function");
}
Old versions of the C programming language permitted function references without earlier declarations. As a legacy, many current compilers still support the old language or aspects of it. This is why some compilers accept the source code you have shown. Your compiler likely has switches that tell it to use a more recent version of the C programming language or to be more strict about adherence to the standard.
C++ was developed more recently and does not have the legacy of functions without declarations.
The different return types work because the assembly language happens to be implemented the same way. For a function returning void, the called routine simply performs its operations and returns. For a function returning int, the called routine performs its operations, puts its final result in a specific processor register, and returns. In the calling routine, when the return value of a function returning int is not used, the calling routine simply ignores what is in the processor register. Because the register is ignored, there is no difference, to the calling routine, between a function returning void and a function returning int. This will not be the case on all target platforms; there can be differences between functions with different return types, especially when the return types are more complicated objects (such as structs). And, if the calling function did use the return value, the return type would make a difference. The function returning void would leave some uncontrolled value in the processor register where a return value is supposed to be, and the calling function would use that and get unexpected results.
As should be apparent, none of this is behavior you should rely on. It is good practice to use the compiler switches that specify you would like stricter adherence to the standard and would like more warnings. (I would prefer these be the default for compilers.) And it is good practice to write code that conforms to the standard.
Because C allows the implicit declaration of functions. Or at least
it did; C90 may require a declaration, I'm not sure. But since not
declaring functions was common practice in C for such a long time, I
would expect most compilers to continue to allow it, even after it is
banned.
Because C and C++ are different languages. C++ has never allowed
implicitly declaring functions.
Because historically, C didn't have a void type; functions with no
return value were declared int, even if they didn't return anything,
and there's no problem as long as you don't attempt to use the
(non-existant) return value.
The error does not show in C because you're not using the proper flags in the invocation of your compiler.
What is your compiler?
If it's gcc, try gcc -std=c99 -pedantic -Werror ...
After reading this discussion I realized that I almost totally misunderstand the matter :)
As the description of C++ abstract machine is not rigorous enough(comparing, for instance, with JVM specification), and if a precise answer isn't possible I would rather want to get informal clarifications about rules that reasonable "good" (non-malicious) implementation should follow.
The key concept of part 1.9 of the Standard addressing implementation freedom is so called as-if rule:
an implementation is free to disregard any requirement of this
Standard as long as the result is as if the requirement had been
obeyed, as far as can be determined from the observable behavior of
the program.
The term "observable behavior", according to the standard (I cite n3092), means the following:
— Access to volatile objects are evaluated strictly according to the
rules of the abstract machine.
— At program termination, all data written into files shall be
identical to one of the possible results that execution of the program
according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take
place in such a fashion that prompting output is actually delivered
before a program waits for input. What constitutes an interactive
device is implementation-defined.
So, roughly speaking, the order and operands of volatile access operations and io operations should be preserved; implementation may make arbitrary changes in the program which preserve these invariants (comparing to some allowed behaviour of the abstract c++ machine)
Is it reasonable to expect that non-malicious implementation treates io operations wide enough (for instance, any system call from user code is treated as such operation)? (E.g. RAII mutex lock/unlock wouldn't be thrown away by compiler in case RAII wrapper contains no volatiles)
How deeply the "behavioral observation" should immerse from user-defined c++ program level into library/system calls? The question is, of course, only about library calls that not intended to have io/volatile access from the user viewpoint (e.g. as new/delete operations) but may (and usually does) access volatiles or io in the library/system implementation. Should the compiler treat such calls from the user viewpoint (and consider such side effects as not observable) or from "library" viewpoint (and consider the side effects as observable) ?
If I need to prevent some code from elimination by compiler, is it a good practice not to ask all the questions above and simply add (possibly fake) volatile access operations (wrap the actions needed to volatile methods and call them on volatile instances of my own classes) in any case that seems suspicious?
Or I'm totally wrong and the compiler is disallowed to remove any c++ code except of cases explicitly mentioned by the standard (as copy elimination)
The important bit is that the compiler must be able to prove that the code has no side effects before it can remove it (or determine which side effects it has and replace it with some equivalent piece of code). In general, and because of the separate compilation model, that means that the compiler is somehow limited as to what library calls have observable behavior and can be eliminated.
As to the deepness of it, it depends on the library implementation. In gcc, the C standard library uses compiler attributes to inform the compiler of potential side effects (or absence of them). For example, strlen is tagged with a pure attribute that allows the compiler to transform this code:
char p[] = "Hi there\n";
for ( int i = 0; i < strlen(p); ++i ) std::cout << p[i];
into
char * p = get_string();
int __length = strlen(p);
for ( int i = 0; i < __length; ++i ) std::cout << p[i];
But without the pure attribute the compiler cannot know whether the function has side effects or not (unless it is inlining it, and gets to see inside the function), and cannot perform the above optimization.
That is, in general, the compiler will not remove code unless it can prove that it has no side effects, i.e. will not affect the outcome of the program. Note that this does not only relate to volatile and io, since any variable change might have observable behavior at a later time.
As to question 3, the compiler will only remove your code if the program behaves exactly as if the code was present (copy elision being an exception), so you should not even care whether the compiler removes it or not. Regarding question 4, the as-if rule stands: If the outcome of the implicit refactor made by the compiler yields the same result, then it is free to perform the change. Consider:
unsigned int fact = 1;
for ( unsigned int i = 1; i < 5; ++i ) fact *= i;
The compiler can freely replace that code with:
unsigned int fact = 120; // I think the math is correct... imagine it is
The loop is gone, but the behavior is the same: each loop interaction does not affect the outcome of the program, and the variable has the correct value at the end of the loop, i.e. if it is later used in some observable operation, the result will be as-if the loop had been executed.
Don't worry too much on what observable behavior and the as-if rule mean, they basically mean that the compiler must yield the output that you programmed in your code, even if it is free to get to that outcome by a different path.
EDIT
#Konrad raises a really good point regarding the initial example I had with strlen: how can the compiler know that strlen calls can be elided? And the answer is that in the original example it cannot, and thus it could not elide the calls. There is nothing telling the compiler that the pointer returned from the get_string() function does not refer to memory that is being modified elsewhere. I have corrected the example to use a local array.
In the modified example, the array is local, and the compiler can verify that there are no other pointers that refer to the same memory. strlen takes a const pointer and so it promises not to modify the contained memory, and the function is pure so it promises not to modify any other state. The array is not modified inside the loop construct, and gathering all that information the compiler can determine that a single call to strlen suffices. Without the pure specifier, the compiler cannot know whether the result of strlen will differ in different invocations and has to call it.
The abstract machine defined by the standard will, given a specific
input, produce one of a set of specific output. In general, all that is
guaranteed is that for that specific input, the compiled code will
produce one of the possible specific output. The devil is in the
details, however, and there are a number of points to keep in mind.
The most important of these is probably the fact that if the program has
undefined behavior, the compiler can do absolutely anything. All bets
are off. Compilers can and do use potential undefined behavior for
optimizing: for example, if the code contains something like *p = (*q) ++,
the compiler can conclude that p and q aren't aliases to the same
variable.
Unspecified behavior can have similar effects: the actual behavior may
depend on the level of optimization. All that is requires is that the
actual output correspond to one of the possible outputs of the abstract
machine.
With regards to volatile, the stadnard does say that access to
volatile objects is observable behavior, but it leaves the meaning of
"access" up to the implementation. In practice, you can't really count
much on volatile these days; actual accesses to volatile objects may
appear to an outside observer in a different order than they occur in
the program. (This is arguably in violation of the intent of the
standard, at the very least. It is, however, the actual situation with
most modern compilers, running on a modern architecture.)
Most implementations treat all system calls as “IO”. With
regards to mutexes, of course: as far as C++03 is concerned, as soon as
you start a second thread, you've got undefined behavior (from the C++
point of view—Posix or Windows do define it), and in C++11,
synchronization primatives are part of the language, and constrain the
set of possible outputs. (The compiler can, of course, elimiate the
synchronizations if it can prove that they weren't necessary.)
The new and delete operators are special cases. They can be
replaced by user defined versions, and those user defined versions may
clearly have observable behavior. The compiler can only remove them if
it has some means of knowing either that they haven't been replaced, of
that the replacements have no observable behavior. In most systems,
replacement is defined at link time, after the compiler has finished its
work, so no changes are allowed.
With regards to your third question: I think you're looking at it from
the wrong angle. Compilers don't “eliminate” code, and no
particular statement in a program is bound to a particular block of
code. Your program (the complete program) defines a particular
semantics, and the compiler must do something which produces an
executable program having those semantics. The most obvious solution
for the compiler writer is to take each statement separately, and
generate code for it, but that's the compiler writer's point of view,
not yours. You put source code in, and get an executable out; but lots
of statements don't result in any code, and even for those that do,
there isn't necessarily a one to one relationship. In this sense, the
idea of “preventing some code elimination” doesn't make
sense: your program has a semantics, specified by the standard, and all
you can ask for (and all that you should be interested in) is that the
final executable have those semantics. (Your fourth point is similar:
the compiler doesn't “remove” any code.)
I can't speak for what the compilers should do, but here's what some compilers actually do
#include <array>
int main()
{
std::array<int, 5> a;
for(size_t p = 0; p<5; ++p)
a[p] = 2*p;
}
assembly output with gcc 4.5.2:
main:
xorl %eax, %eax
ret
replacing array with vector shows that new/delete are not subject to elimination:
#include <vector>
int main()
{
std::vector<int> a(5);
for(size_t p = 0; p<5; ++p)
a[p] = 2*p;
}
assembly output with gcc 4.5.2:
main:
subq $8, %rsp
movl $20, %edi
call _Znwm # operator new(unsigned long)
movl $0, (%rax)
movl $2, 4(%rax)
movq %rax, %rdi
movl $4, 8(%rax)
movl $6, 12(%rax)
movl $8, 16(%rax)
call _ZdlPv # operator delete(void*)
xorl %eax, %eax
addq $8, %rsp
ret
My best guess is that if the implementation of a function call is not available to the compiler, it has to treat it as possibly having observable side-effects.
1. Is it reasonable to expect that non-malicious implementation treates io operations wide enough
Yes. Assuming side-effects is the default. Beyond default, compilers must prove things (except for copy-elimination).
2. How deeply the "behavioral observation" should immerse from user-defined c++ program level into library/system calls?
As deep as it can. Using current standard C++ the compiler can't look behind library with meaning of static library, i.e. calls that target a function inside some ".a-" or ".lib file" calls, so side effects are assumed.
Using the traditional compilation model with multiple object files, the compiler is even unable to look behind extern calls. Optimizations accross
units of compilation may be done at link-time though.
Btw, some compilers have an extension to tell it about pure functions. From the gcc documentation:
Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure. For example,
int square (int) __attribute__ ((pure));
says that the hypothetical function square is safe to call fewer times than the program says.
Some of common examples of pure functions are strlen or memcmp. Interesting non-pure functions
are functions with infinite loops or those depending on volatile memory or other system resource,
that may change between two consecutive calls (such as feof in a multithreading environment).
Thinking about poses an interesting question to me: If some chunk of code mutates a non-local variable, and calls an un-introspectible function,
will it assume that this extern function might depend on that non-local variable?
compilation-unit A:
int foo() {
extern int x;
return x;
}
compilation-unit B:
int x;
int bar() {
for (x=0; x<10; ++x) {
std::cout << foo() << '\n';
}
}
The current standard has a notion of sequence points. I guess if a compiler does not see enough,
it can only optimize as far as to not break the ordering of dependent sequence points.
3. If I need to prevent some code from elimination by compiler
Except by looking at the object-dump, how could you judge whether something was removed?
And if you can't judge, than is this not equivalent to the impossibility of writing code that depends on its (non-)removal?
In that respect, compiler extensions (like for example OpenMP) help you in being able to judge. Some builtin mechanisms exist, too, like volatile variables.
Does a tree exist if nobody can observe it? Et hop, we are at quantum mechanics.
4. Or I'm totally wrong and the compiler is disallowed to remove any c++ code except of cases explicitly mentioned by the standard (as copy elimination)
No, it is perfectly allowed so. It is also allowed to transform code like it's a piece of slime.
(with the exception of copy elimination, you couldn't judge anyways).
One difference is that Java is designed to run on one platform only, the JVM. That makes it much easier to be "rigorous enough" in the specification, as there is only the platform to consider and you can document exactly how it works.
C++ is designed to be able to run on a wide selection of platforms and do that natively, without an intervening abstraction layer, but use the underlying hardware functionality directly. Therefore it has chosen to allow the functionality that actually exist on different platforms. For example, the result of some shift operations like int(1) << 33 is allowed to be different on different system, because that's the way the hardware works.
The C++ standard describes the result you can expect from your program, not the way it has to be achieved. In some cases it says that you have to check you particular implementation, because the results may differ but still be what is expected there.
For example, on an IBM mainframe nobody expects floating point to be IEEE compatible because the mainframe series is much older that the IEEE standard. Still C++ allows the use of the underlying hardware while Java does not. Is that an advantage or a disavantage for either language? It depends!
Within the restrictions and allowances of the language, a reasonable implementation must behave as if it did like you have coded in your program. If you do system calls like locking a mutex, the compiler has the options of not knowing what the calls do and therefore cannot remove them, or do know exactly what they do and therefore also know if they can be removed or not. The result is the same!
If you do calls to the standard library, the compiler can very well know exactly what the call does, as this is described in the standard. It then has the option of really calling a function, replace it with some other code, or skip it entirely if it has no effect. For example, std::strlen("Hello world!") can be replaced by 12. Some compilers do that, and you will not notice.
I have found a book that states that if you want to use a function from the C standard library which takes a function pointer as an argument (for example qsort), the function of which you want to pass the function pointer needs to be a C function and therefore declared as extern "C".
e.g.
extern "C" {
int foo(void const* a, void const* b) {...}
}
...
qsort(some_array, some_num, some_size, &foo);
I would not be surprised if this is just wrong information, however - I'm not sure, so: is this correct?
A lot depends on whether you're interested in a practical answer for the compiler you're using right now, or whether you care about a theoretical answer that covers all possible conforming implementations of C++. In theory it's necessary. In reality, you can usually get by without it.
The real question is whether your compiler uses a different calling convention for calling a global C++ function than when calling a C function. Most compilers use the same calling convention either way, so the call will work without the extern "C" declaration.
The standard doesn't guarantee that though, so in theory there could be a compiler that used different calling conventions for the two. At least offhand, I don't know of a compiler like that, but given the number of compilers around, it wouldn't surprise me terribly if there was one that I don't know about.
OTOH, it does raise another question: if you're using C++, why are you using qsort at all? In C++, std::sort is almost always preferable -- easier to use and usually faster as well.
This is incorrect information.
extern C is needed when you need to link a C++ library into a C binary; it allows the C linker to find the function names. This is not an issue with function pointers (as the function is not referenced by name in the C code).