parameter dropping when using C linkage in a C++ program - c++

I have the following code in main.cpp
extern "C"
{
void bar(int x, char* s);
}
int main()
{
bar(5, "hello");
}
Notice that function bar is declared as taking two arguments. This is then compiled and linked to a static library bar.cpp that contains this code
#include <iostream>
extern "C"
{
void bar(int x)
{
std::cout << x;
}
}
Notice function bar takes only one argument.
The executable compiles successfully and prints 5
I have three questions:
Shouldn't there have been a compiler error indicating the mismatch in the number of parameters?
In the scenario above, since the string hello is not received by bar, when and how is it destroyed?
Is it completely valid to write and use code as above (knowing parameters will be dropped)? What exactly are the semantics behind parameter dropping?

Although your specify VS, the question is more generally answered about C++, compilers, and execution platforms in general.
1.) You instructed the compiler to follow the C style calling convention for your platform to reference a symbol not defined in that compilation unit. The compiler then generates an object which tells the linker "call _bar here" (may be bar depending on your platform), which happily resolves to the compilation output of bar.cpp. The older C++ calling conventions would result in mangled names like barZ8intZP8char or worse depending on your compiler, to ensure overloading worked properly. However newer compilers are possibly smarter (magic!) and may understand additional metadata stored in the object file.
A bigger issue for multi-platform code is concerned with stack ordering. On a few platforms parameters are stored in reverse order on the stack than their declaration, thus your code would then be provided with the address of the string instead of the integer value. Fine for printing an integer, but would result in (hopefully) a segfault with the first parameter being a string and the second being an integer in the function declaration.
2.) This depends on the platform you are using. For most platforms related to the IA32 systems (x86, AMD64, IA64, etc), the caller is responsible for managing the parameters on the stack. Thus the stack frame containing the extra parameter is discarded in full when the call is complete. There are optimization cases where this may trigger a discrete bug where a frame is reused because the compiler was misinformed regarding the call stack.
3.) For application programming I would consider this a bad practice as it may introduce very hard to diagnose bugs. I'm sure some one has found an edge case to that statement regarding binary compatibility; however I would prefer the compiler to be aware of the parameters to avoid the optimization bugs referred to in #2.

Related

Why C++ compiler isn't optimizing unused reference variables?

Consider following program:
#include <iostream>
struct Test
{
int& ref1;
int& ref2;
int& ref3;
};
int main()
{
std::cout<<sizeof(Test)<<'\n';
}
I know that C++ compiler can optimize the reference variables entirely so that they won't take any space in memory at all.
I tested a above demo program to see the output.
But when I compile & run on g++ 4.8.1 it gives me output 12.
It looks like compiler isn't optimizing the reference variables. I was expecting size of the Test struct to be 1.
I've also used -Os command line option but it still gives me output 12. I have also tried this program on MSVS 2010
compiled with /Ox command line option but it looks like Microsoft compiler isn't performing any optimization at all.
The three reference variables are unused & they aren't associated with any other variable. Then why compilers aren't optimizing them?
The size of the struct stays the same, there is nothing to optimize. If you would like to create an array of Test it should allocate the right size for each Test. The compiler cannot know which will be used or not. That's why there is no such optimization.
Unused variables would be for example a new int& int inside your main function. If this is unused, the optimizer will optimize it away.
Theoretically, if the world would only consist of simple programs, the compiler could optimize the sizeof of this struct to 1, because the sizeof of a struct is unspecified.
But in our real world, we have separate compilation of shared libraries that the compiler when compiling your code has no clue about (for example you could LoadLibrary or dlopen) that also happen to define your struct and where the sizeof should better agree with that in your program.
So actually a compiler better doesn't opimize the sizeof to 1 :)
In 8.3.2.4, of the C++ standard, it is said
It is unspecified whether or not a reference requires storage
So, the standard leaves it open to the implementation how references should be implemented. This implies that the size of your struct can be non-zero.
If the compiler would remove the references from the struct, you would not be able to link code compiled with different compiler settings. Imagine you compile one translation unit with optimizations, the other one without and link them together and pass an object from one TU to the other. Which size should the code assume? A function in TU 1 allocates 12 bytes on the stack, while a function in TU 2 allocates some other space.
The compiler can optimize your program and e.g. remove temporary objects, assignments etc. It may that you create an object of your struct somewhere in your source code and use it, but it will not be seen in the assembler code because it is not needed. What compilers also frequently do is remove indirections, e.g. by replacing references with direct access.

Marking a function as having no side-effects with Visual C++

Consider the following (a bit conceived) example:
// a.cpp
int mystrlen(const char* a) {
int l = 0;
while (a[l]) ++l;
return l;
}
// b.cpp
extern int mystrlen(const char*);
int foo(const char* text) {
return mystrlen(text) + mystrlen(text);
}
It would be very nice to be able to tell the compiler that mystrlen() doesn't have side-effects and thus it can re-use the old result from mystrlen(text) instead of calling it twice.
I don't find anything in the docs about it and restrict or one of its variances doesn't seem to do the job, either. A look at the output code with all optimizations on (switch /Ox) shows that the compiler really generates two calls. It even does so if I put both functions in one module.
Any solution to this or can anyone confirm that there is no solution in VC++?
MSVC has no support for pure/const attributes, and also has no intention to support them. See https://connect.microsoft.com/VisualStudio/feedback/details/804288/msvc-add-const-and-pure-like-function-attributes. Other compilers, such as GCC and Clang do support such attributes. Also see pure/const function attributes in different compilers.
What you are looking for won't help you.
In general, the compiler can't elide the calls, even if if believes the function is without side effects. Where did you get that pointer? Does a signal handler have access to that same pointer? Maybe another thread? How does the compiler know the memory pointed to by the pointer isn't going to change out from underneath it?
Compiler's do frequently eliminate redundant fetches within a function body, even for things fetched through pointers. But there is a limit to how much of this they can or even should do.
Here you're asking the compiler to believe that a bare pointer you have to who knows where will maintain consistent contents between two function calls. That's a lot of assuming. Sure you haven't declared your pointer volatile, but still, it's a lot of assuming.
Now, if you had a buffer on the stack and were passing it to that function twice in a row, the compiler can pretty safely assume that if you haven't passed the pointer out somewhere else that the contents of that buffer aren't going to be changed by some random other thing in the program at some unexpected time.
For example:
// b.cpp
extern int mystrlen(const char*);
int foo(int bar) {
char number[20];
snsprintf(number, 20, "%d", bar);
return mystrlen(number) + mystrlen(number);
}
Given assumptions the compiler could make about what snprintf did with number given that it's a library function, it could then elide the second call to mystrlen if there was a way to declare the mystrlen had no side effects.
Because C++ is an imperative language rather than a functional one, what you're trying to achieve is not possible.
It looks like the behaviour that you're expecting here is is that of referential transparency, which there isn't a way to tell the compiler about in C++ (but in a purely functional programming language like Haskell would be implicit).
Hopefully a future standard of C++ will introduce a keyword that will allow us to mark functions as 'pure' or 'without side effect'.

How CRT calls main , having different parameter

We can write main function in several ways,
int main()
int main(int argc,char *argv[])
int main(int argc,char *argv[],char * environment)
How run-time CRT function knows which main should be called. Please notice here, I am not asking about Unicode supported or not.
The accepted answer is incorrect, there's no special code in the CRT to recognize the kind of main() declaration.
It works because of the cdecl calling convention. Which specifies that arguments are pushed on the stack from right to left and that the caller cleans up the stack after the call. So the CRT simply passes all arguments to main() and pops them again when main() returns. The only thing you need to do is specify the arguments in the right order in your main() function declaration. The argc parameter has to be first, it is the one on the top of the stack. argv has to be second, etcetera. Omitting an argument makes no difference, as long as you omit all the ones that follow as well.
This is also why the printf() function can work, it has a variable number of arguments. With one argument in a known position, the first one.
In general, the compiler/linker would need to recognise the particular form of main that you are using and then include code to adapt that from the system startup function to your C or C++ main function.
It is true that specific compilers on specific platforms could get away without doing this, using the methods that Hans describes in his answer. However, not all platforms use the stack to pass parameters, and it is possible to write conforming C and C++ implementations which have incompatible parameter lists. For such cases, then the compiler/linker would need to determine which form of main to call.
Hmmm. It seems that perhaps the currently accepted answer, which indicates that the previously accepted answer is incorrect, is itself incorrect. The tags on this question indicate it applies to C++ as well as C, so I’ll stick to the C++ spec, not C99. Regardless of all other explanations or arguments, the primary answer to this question is that “main() is treated special in an implementation-defined way.” I believe that David's answer is technically more correct than Hans', but I'll explain it in more detail....
The main() function is a funny one, treated by the compiler & linker with behavior that matches no other function. Hans is correct that there is no special code in the CRT to recognize different signatures of main(), but his assertion that it “works because of the cdecl calling convention” applies only to specific platform(s), notably Visual Studio. The real reason that there’s no special code in the CRT to recognize different signatures of main() is that there’s no need to. And though it’s sort of splitting hairs, it’s the linker whose job it is to tie the startup code into main() at link time, it’s not the CRT’s job at startup time.
Much of how the main() function is treated is implementation-defined, as per the C++ spec (see Section 3.6, “Start and termination”). It’s likely that most implementations’ compilers treat main() implicitly with something akin to extern “C” linkage, leaving main() in a non-decorated state so that regardless of its function prototype, its linker symbol is the same. Alternatively, the linker for an implementation could be smart enough to scan through the symbol table looking for any whose decorated name resolves to some form of “[int|void] main(...)” (note that void as a return type is itself an implementation-specific thing, as the spec itself says that the return type of main() must be ‘int’). Once such a function is found in the available symbols, the linker could simply use that where the startup code refers to “main()”, so the exact symbol name doesn’t necessarily have to match anything in particular; it could even be wmain() or other, as long as either the linker knows what variations to look for, or the compiler endows all of the variations with the same symbol name.
Also key to note is that the spec says that main() may not be overloaded, so the linker shouldn’t have to “pick” between multiple user implementations of various forms of main(). If it finds more than one, that’s a duplicate symbol error (or other similar error) even if the argument lists don’t match. And though all implementations “shall” allow both
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
they are also permitted to allow other argument lists, including the version you show that includes an environment string array pointer, and any other variation that makes sense in any given implementation.
As Hans indicates, the Visual Studio compiler’s cdecl calling convention (and calling conventions of many other compilers) provide a framework wherein a caller can set up the calling environment (i.e. the stack, or ABI-defined registers, or some combination of the two) in such a way that a variable number of arguments can be passed, and when the callee returns, the caller is responsible for cleanup (popping the used argument space off the stack, or in the case of registers, nothing needs done for cleanup). This setup lends itself neatly to the startup code passing more parameters than might be needed, and the user’s main() implementation is free to use or not use any of these arguments, as is the case with many platforms’ treatment of the various forms of main() you list in your question. However, this is not the only way a compiler+linker could accomplish this goal: Instead, the linker could choose between various versions of the startup code based on the definition of your main(). Doing so would allow a wide variety of main() argument lists that would otherwise be impossible with the cdecl caller-cleanup model. And since all of that is implementation-defined, it’s legal per the C++ spec, as long as the compiler+linker supports at least the two combinations shown above (int main() and int main(int, char**)).
The C 99 Standard (5.1.2.2.1 Program startup) says that an implementation enforces no prototype for the main() function, and that a program can define it as either of:
1) int main(void);
2) int main(int argc, char *argv[]);
or in a manner semantically equivalent to 2), e.g.
2') int main(int argc, char **argv);
or in other implementation defined ways. It does not mandate that the prototype:
3) int main(int argc, char *argv[],char * envp[]);
will have the intended behaviour - although that prototype must compile, because any prototype must compile. 3) is supported by GCC and Microsoft C among other compilers. (N.B. The questioner's
3rd prototype has char *envp rather than char *envp[], whether by accident or because he/she has some other compiler).
Both GCC and Microsoft C will compile main() with any prototype whatsoever, as they ought to. They parse the prototype that you actually specify and generate assembly language to consume the arguments, if any, in the correct manner. Thus for example they will each generate the expected behaviour for the program:
#include <stdio.h>
void main(double d, char c)
{
printf("%lf\n",d);
putchar(c);
}
if you could find a way of passing a double and a char directly to the program, not via an array of strings.
These observations can be verified by enabling the assembly language listings for experimental programs.
The question of how the compiler's standard CRT permits us to invoke the generated implementation of main() is distinct from the question of how main() may be defined to the compiler.
For both GCC and MS C, main() may defined any way we like. In each case however the implemention's standard CRT, AFIK, supports passing arguments to main() only than as per 3). So 1) - 2') will also have the expected behavior by ignoring excess arguments, and we have no other options short of providing a non-standard runtime of our own.
Hans Passant's answer seems incidentally misleading in suggesting that argc tells the function how many subsequent arguments to consume in the same manner as the first argument to printf(). If argc is present at all, it only denotes the number of elements in the the array passed as the second argument argv. It does not indicate how many arguments are passed to main(). Both GCC and MS C figure out how what arguments are expected by parsing the prototype that you write - essentially what a compiler does with any function except those, like printf(), that
are defined to take a variable number of arguments.
main() does not take a variable number of arguments. It takes the arguments you specify in your definition, and the standard CRTs of the usual compilers assume them to be (int, char *[], char *[]).
First, the main function is treated specifically in GCC (e.g. the main_identifier_node in file gcc/c-family/c-common.c of the source tree of GCC 4.7)
And the C11 and C++11 standards have specific wording and specification about it.
Then, the C calling ABI conventions are usually so that extra arguments don't harm much.
So you can think of it as if both the language specification and the compiler have specific things regarding "overloading" of main.
I even think that main might not be an ordinary function. I believe that some words in the standard -which I don't have right now- might be e.g. understood as forbidding taking its address or recursing on main.
In practice, main is called by some assembly code compiled into crt*.o files linked by gcc. Use gcc -v to understand more what is happenning.

C/C++ unused inline function undefined reference

Consider the following code (this is not pthread specific; other examples, such as those involving the realtime library, exhibit similar behavior):
#define _GNU_SOURCE
#include <pthread.h>
inline void foo() {
static cpu_set_t cpuset;
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
}
int main(int argc, char *argv[]) { }
This is a valid program in C and in C++. So I save the contents of this to testc.c and testcpp.cpp and try to build.
When I build in C++ I get no error. When I build in C I get an undefined reference error. Now, this error occurs in -O1 and in -O3. Is there anyway to instruct gcc to do the right thing (see that foo is unused and skip the requirement for a definition of pthread_setaffinity_np)?
EDIT: I thought it was obvious from context, but the error message is:
/tmp/ccgARGVJ.o: In function `foo':
testc.c:(.text+0x17): undefined reference to `pthread_setaffinity_np'
Note that since foo isn't being referenced in the main path, g++ correctly ignores the function entirely but gcc does not.
EDIT 2: Let me try this one more time. The function foo, and the subsequent call to pthread_setaffinity_np, is unused. The main function is empty. Just look at it! Somehow, g++ figured out that foo did not need to be included, and subsequently the build process did not trip up when we intentionally omitted -lpthread (and checking the exported symbols with nm confirms that neither foo nor reference to pthread_setaffinity_np were needed). The resultant output from gcc didn't pick up on that fact.
I am asking this question because the C++ and the C frontends seem to give different results on the same input. This doesn't seem to be an ld issue prima facie because I would expect both paths to give the same linking error, which is why I emphasized that it seems to be a compiler issue. If both C++ and C gave problems, then yes I would agree that its a linking issue.
Well, apparently your program contains an error: you declare and call function pthread_setaffinity_np, but you never define it. Apparently you forgot to supply the library that contains the definition. This is an error in both C and C++.
In other words, this is not a valid program in C and in C++. It violates the One Definition Rule of C++ (and whatever the similar rule is called in C).
The rest depends on whether the compiler will catch this error and issue a diagnostic message for it. While formally the compiler is supposed to catch it, in reality linking errors are not always caught by the compilation process (in extended sense of the term, i.e. including linking as well).
Whether they are caught or not might depend on many factors. In this particular case the factor that matters is apparently the difference between the properties of inline functions of C and C++ languages. (And yes, they are really different between C and C++). I would guess that in C++ mode the compiler decided that this inline function does not need the actual body, while in C mode it decided to generate the body anyway.
So, again, if this program, somehow successfully compiles in some circumstances, it is only because you got lucky. You seem to believe that a function that is not called is supposed to be "ignored entirely". Neither C nor C++ make such guarantees. Assuming that the definition of pthread_setaffinity_np is indeed missing, your program is invalid in both C and C++. For this reason, the compiler that refused to compile it is actually the one with the correct behavior.
Taking the above into account, you might want to ask yourself whether you really care about why you got different error reports in C and C++ modes. If you do, it will require some research into the internal mechanics of that specific implementation and won't have much to do with the languages themselves.
In C, the inline keyword does not affect the linkage of the function. Thus foo has external linkage, and cannot be optimized out because it might be called from another translation unit. If the compiler/assembler put functions in their own individual sections and the linker is able to discard unneeded function sections at link time, it might be able to avoid a linking error, but to be correct, since this program references pthread_setaffinity_np, it must contain a definition for that function somewhere anyway, i.e. you must use -lpthread or equivalent.
In C++, inline functions have internal some weird pseudo-external linkage by default, so gcc optimized it out. See the comments for details.
In short, the lack of an error in certain configurations is a failure of gcc to diagnose an invalid program. It's not the behavior you should expect.
The other lesson you should take away from this is that C and C++ are nowhere near the same thing. Choose which one you're writing and stick to it! Don't try to write code that's "interchangeable" between the two or you're likely to make it subtly incorrect in both...
inline is only a suggestion, not something a compiler is obligated to listen to, so it can't assume that foo is not used in another compilation unit.
But, yeah, it would be nice to know exactly which is the undefined reference, given that you didn't post the error, and odd that it's shows up in C and not C++ compilation.
foo might not be used in your source code, but it's almost certainly referenced elsewhere in the build process and consequently it needs to be compiled.
Especially since a lot of optimization occur in the linking process, because the linker can determine that a function is "dead" and can be discarded.
If, internally, the linker decides to assemble the entire program as one pass, and then optimization in another, I would expect you to see this error (how can it assemble the whole program?)
Further, if the function is to be exported then it most certainly has to be compiled, linked, and end up in the output.
It sounds like you're relying on compiler/linker specific behavior.

Compiler Optimization with Parameters

Lets say you have some functions in some classes are called together like this
myclass::render(int offset_x, int offset_y)
{
otherClass.render(offset_x, offset_y)
}
This pattern will repeat for a while possibly through 10+ classes, so my question is:
Are modern C++ compilers smart enough to recognise that wherever the program stores function parameters - From what wikipedia tells me it seems to vary depending on parameter size, but that for a 2 parameter function the processor register seems likely - doesn't need to be overridden with new values?
If not I might need to look at implementing my own methods
I think it's more likely that the compiler will make a larger-scale optimization. You'd have to examine the actual machine code produced, but for example the following trivial attempt:
#include <iostream>
class B {
public:
void F( int x, int y ) {
std::cout << x << ", " << y << std::endl;
}
};
class A {
B b;
public:
void F( int x, int y ) {
b.F( x, y );
}
};
int main() {
A a;
a.F( 32, 64 );
}
causes the compiler (cl.exe from VS 2010, empty project, vanilla 'Release' configuration) to produce assembly that completely inlines the call tree; you basically get "push 40h, push 20h, call std::operator<<."
Abusing __declspec(noinline) causes cl.exe to realize that A::F just forwards to B::F and the definition of A::F is nothing but "call A::F" without stack or register manipulation at all (so in that case, it has performed the optimization you're asking about). But do note that my example is extremely contrived and so says nothing about the compiler's ability to do this well in general, only that it can be done.
In your real-world scenario, you'll have to examine the disassembly yourself. In particular, the 'this' parameter needs to be accounted for (cl.exe usually passes it via the ECX register) -- if you do any manipulation of the class member variables that may impact the results.
Yes, it is. The compiler performs dataflow analysis before register allocation, keeping track of which data is where at which time. And it will see that the arg0 location contains the value that needs to be in the arg0 location in order to call the next function, and so it doesn't need to move the data around.
I'm not a specialist, but it looks a lot like the perfect forwarding problem that will be solved in the next standard (C++0x) by using rvalue-references.
Currently I'd say it depend on the compiler, but I guess if the function and the parametters are simple enough then yes the function will serve as a shortcut.
If this function is imlpemented directly in the class definition (and then becoming implicitely candidate for inlining) it might be inligned, making the call directly call the wanted function instead of having two runtime calls.
In spite of your comment, I think that inlining is germane to this discussion. I don't believe that C++ compilers will do what you're asking (reuse parameters on the stack) UNLESS it also inlines the method completely.
The reason is that if it's making a real function call it still has to put the return address onto the stack, thus making the previous call's parameters no longer at the expected place on the stack. Thus in turn is has to put the parameters back on the stack a second time.
However I really wouldn't worry about that. Unless you're making a ridiculous number of function calls like this AND profiling shows that it's spending a large proportion of its time on these calls they're probably extremely minimal overhead and you shouldn't worry about it. For a function that small however, mark it inline and let the compiler decide if it can inline it away completely.
If I understand the question correctly, you are asking "Are most compilers smart enough to inline a simple function like this", and the answer to that question is yes. Note however the implicit this paremeter which is part of your function (because your function is part of a class), so it might not be completely inlineable if the call level is deep enough.
The problem with inlining is that the compiler will probably only be able to do this for a given compilation unit. The linker is probably less likely to be clever enough to inline from one compilation unit to another.
But given the total trivial nature of the function and that both functions have exactly the same arguments in the same order, the cost of the function call will probably be only one machine instruction viz. an additional branch (or jump) to the true implementation. There is no need to even push the return address onto the stack.