This question states that main can be implementation defined with some restrictions.
So, I wrote the following C++ code to try out the following signature of main:
main.h
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int i) {
this->i = i;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
main.c++
#include <iostream>
#include "main.h"
int main(MyClass myClass) {
std::cout << myClass.geti() << std::endl;
return 0;
}
Which Gives the following results:
The command g++ -o main main.c++ -O3 compiles successfully with warnings:
main.c++:5:5: warning: first argument of ‘int main(MyClass)’ should be ‘int’ [-Wmain]
5 | int main(MyClass myClass) {
| ^~~~
main.c++:5:5: warning: ‘int main(MyClass)’ takes only zero or two arguments [-Wmain]
The command clang++ -o main main.c++ -std=c++14 gives the error:
main.c++:5:5: error: first parameter of 'main' (argument count) must be of type 'int'
int main(MyClass myClass) {
^
1 error generated.
the main file generated by g++ gives SIGSEGV (why though?)
So, if main can be implementation defined, why does clang give an error while g++ generated file give SIGSEGV?
I also went further and created a different code so that I will be able to pass a MyClass object to main.c++ as follows:
#include <iostream>
#include "main.h"
#include <unistd.h>
int main() {
MyClass myClass;
execve("./main",myClass,NULL);
return 0;
}
However, as execve takes the second parameter to be a char* const *, it does not compile. How do I pass the myClass object to the main file generated by g++?
The command g++ -o main main.c++ -O3 compiles successfully with warnings
This is not successful compilation. You should always use -Werror. If you fail to do so and then decide to ignore the warning and proceed with running the program, it's your own responsibility. You better know full well what you are doing. See this for more information.
the main file generated by g++ gives SIGSEGV (why though?)
The compiler has warned you. It is in your best interest to listen to it. If things go boom, chances are, that's because you have ignored warnings.
why does clang give an error while g++ generated file give SIGSEGV?
The program is not a valid C++ program. There is no meaningful difference between a warning and an error.
How do I pass the myClass object to the main file generated by g++?
You cannot. main must have a form equivalent to one of these two:
int main()
int main(int argc, char* argv[])
(Optional reading in italics) Other forms of main are implementation-defined. This means your implementation needs to support them in a documented way. Unless you have read documentation for your implementation and found that it supports the form of main you want, there's no way to do that.
Other than having an implementation-defined main, the only way a program can get hold of an object of a class type is by constructing that object.
You are close. You have identified your primary issue attempting to pass as a parameter to main() -- that won't work. The declaration for main() is defined by the standard and you are limited to passing string values (nul-terminated character arrays... C-Strings) in as arguments.
In your case you need to create an instance of your class within main(), e.g.
#include <iostream>
#include "main.h"
int main() {
MyClass myClass;
std::cout << myClass.geti() << std::endl;
return 0;
}
Your main.h header has a variable shadowing problem where at line 10:
inline void seti(int i) {
int i shadows a prior declaration at line 3, e.g. int i; (though the consequence would be unlikely to matter). Just replace the variable name in the second declaration with j (or whatever you like). Your code will compile without warning, e.g.
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int j) {
this->i = j;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
Example Use/Output
$ ./bin/main
2
You can also call your seti() function to update the private variable in your class, e.g.
myClass.seti(5);
std::cout << myClass.geti() << std::endl;
Which would now output 5.
Let me know if you have further questions.
Related
Consider this code:
#include <cstdio>
int get_value() { asm("movl $254, %eax"); }
int main() { printf("%d\n", get_value()); }
Now if one compiles this code with g++ main.cpp, one gets a compiler warning (but the code still compiles):
main.cpp: In function ‘int get_value()’:
main.cpp:3:43: warning: no return statement in function returning non-void [-Wreturn-type]
3 | int get_value() { asm("movl $254, %eax"); }
|
As this answer says that if a compiler generates a binary with the above code, all bets are off. (no return statement from a function with return type int)
Indeed, when one compiles this code with optimization turned on g++ -O3 main.cpp, this program immediately segfaults.
So my question is how can one return from inline assembly within a c++ function that is conformant with C++, and one doesn't get this warning, and the code works fine.
I believe what you have to do is declare a dummy variable, and use the gcc extended syntax to output that variable, and then you can return that variable. The optimiser should strip both assignents out.
It is sort-of explained in https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5, and might look like this:
#include <cstdio>
int get_value() {
int b;
asm("movl $254, %0;"
: "=r"(b)
);
return b;
}
int main() {
printf("%d\n", get_value());
}
I have a little piece of code in C++:
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main() {
int i=0;
istream_iterator<string> EOS;
double x;
return 0;
}
Now i compile it with my g++ (GCC) 4.4.4
g++ -W -Wall -pedantic test.cc -o test
And get:
test.cc: In function 'int main()':
test.cc:9: warning: unused variable 'i'
test.cc:11: warning: unused variable 'x'
Why there is no warning for unused EOS?
It is not a primitive value, so its constructor and/or destructor might have desired side effects.
To illustrate that this happens in practice: I use a class to time sections of code, that looks roughly like this:
class Timed {
double start;
public:
Timed() { start = now(); }
~Timed() { std::cout << (now() - start) << '\n'; }
}
So to measure how long a function takes, I simply do:
void slow() {
Timed t;
// heavy operation here...
}
The variable t never gets used, but it's still important to the behaviour of the code.
istream_iterator<string> has a constructor, so the declaration of EOS isn't really a no-op like the declarations of i and x are.
Often you want to declare a class-type object and then not do anything with it. For example, consider std::lock_guard in C++0x (boost::scoped_lock in Boost) or any other kind of scope guard class. You don't usually want to do anything with that kind of object, you just want to create the object so that its destructor get run at the end of the block to perform whatever cleanup needs to be performed.
Because you could have done that with a purpose. It's not a primitive. Maybe the constructor and destructor do something important?
MFC even had classes that operated that way, you could do this:
void foo()
{
CWaitCursor cursor;
[...]
}
That would display an hourglass icon for the duration of the function.
#include <iostream>
using namespace std;
class test{
public:
test() { cout<<"CTOR"<<endl; }
~test() { cout<<"DTOR"<<endl; }
};
int main()
{
test testObj();
cout<<"HERE"<<endl;
}
Output:
HERE
Compiler skips the line "test testObj(); " and compiles the rest with warning and when run will generate the output. The warning is "prototyped function not called (was a variable definition intended?) in VC++ 2008. Why does it not throw an error?
Because it's not an error.
Your code has fallen foul of the most-vexing parse (in summary, test testObj(); doesn't define a variable, it declares a function).
Simply, because it's not an error to declare a function such as the one you declared. The warning should be useful enough, though.
Remove the () from the constructor call in Main
int main()
{
test testObj;
cout<<"HERE"<<endl;
}
I have a little piece of code in C++:
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main() {
int i=0;
istream_iterator<string> EOS;
double x;
return 0;
}
Now i compile it with my g++ (GCC) 4.4.4
g++ -W -Wall -pedantic test.cc -o test
And get:
test.cc: In function 'int main()':
test.cc:9: warning: unused variable 'i'
test.cc:11: warning: unused variable 'x'
Why there is no warning for unused EOS?
It is not a primitive value, so its constructor and/or destructor might have desired side effects.
To illustrate that this happens in practice: I use a class to time sections of code, that looks roughly like this:
class Timed {
double start;
public:
Timed() { start = now(); }
~Timed() { std::cout << (now() - start) << '\n'; }
}
So to measure how long a function takes, I simply do:
void slow() {
Timed t;
// heavy operation here...
}
The variable t never gets used, but it's still important to the behaviour of the code.
istream_iterator<string> has a constructor, so the declaration of EOS isn't really a no-op like the declarations of i and x are.
Often you want to declare a class-type object and then not do anything with it. For example, consider std::lock_guard in C++0x (boost::scoped_lock in Boost) or any other kind of scope guard class. You don't usually want to do anything with that kind of object, you just want to create the object so that its destructor get run at the end of the block to perform whatever cleanup needs to be performed.
Because you could have done that with a purpose. It's not a primitive. Maybe the constructor and destructor do something important?
MFC even had classes that operated that way, you could do this:
void foo()
{
CWaitCursor cursor;
[...]
}
That would display an hourglass icon for the duration of the function.
I've found some strange code...
//in file ClassA.h:
class ClassA {
public:
void Enable( bool enable );
};
//in file ClassA.cpp
#include <ClassA.h>
void ClassA::Enable( bool enable = true )
{
//implementation is irrelevant
}
//in Consumer.cpp
#include <ClassA.h>
....
ClassA classA;
classA.Enable( true );
Obviously since Consumer.cpp only included ClassA.h and not ClassA.cpp the compiler will not be able to see that the parameter has a default value.
When would the declared default value of ClassA::Enable in the signature of the method implementation have any effect? Would this only happen when the method is called from within files that include the ClassA.cpp?
Default values are just a compile time thing. There's no such thing as default value in compiled code (no metadata or things like that). It's basically a compiler replacement for "if you don't write anything, I'll specify that for you." So, if the compiler can't see the default value, it assumes there's not one.
Demo:
// test.h
class Test { public: int testing(int input); };
// main.cpp
#include <iostream>
// removing the default value here will cause an error in the call in `main`:
class Test { public: int testing(int input = 42); };
int f();
int main() {
Test t;
std::cout << t.testing() // 42
<< " " << f() // 1000
<< std::endl;
return 0;
}
// test.cpp
#include "test.h"
int Test::testing(int input = 1000) { return input; }
int f() { Test t; return t.testing(); }
Test:
g++ main.cpp test.cpp
./a.out
Let me admit first that this is the first time I have seen this type of code. Putting a default value in header file IS the normal practice but this isn't.
My guess is that this default value can only be used from code written in the same file and this way the programmer who wrote this wanted to put it in some type of easiness in calling the function but he didn't want to disturb the interface (the header file) visible to the outside world.
Would this only happen when the method
is called from within files that
include the ClassA.cpp?
That's correct. But note that doing so will almost certainly produce multiple definition errors, so the default is only really available from its point of definition within ClassA.cpp.
Put the default value in the declaration, not the definition.
class ClassA {
public:
void Enable( bool enable = true );
};