Objective-C variables read as null in C++ - c++

I'm writing a cross-platform application and need to pass across argc and argv from Objective-C in Xcode to my generic argument handler class in C++. I have a global pointer to this handler class which I set with a new command, but because I can't do new in Objective-C I'm trying the following:
I have a header file called MacCommandLineArgs.h which contains only the following:
static int cmdlArgc = 0;
static const char** cmdlArgv = NULL;
I then set these from within main.m:
int main(int argc, char *argv[])
{
cmdlArgc = argc;
cmdlArgv = (const char**)argv;
return NSApplicationMain(argc, (const char **)argv);
}
Once the Objective-C++ section of the application has been entered, I try to read back these global variables in order to pass them to the pure-C++ class:
int argc = cmdlArgc;
const char** argv = cmdlArgv;
globalCommandLineArgs = new CCommandLineArgs(argc, argv);
When stepping through with the debugger, cmdlArgc and cmdlArgv show up as valid data but argc and argv are still 0 and NULL after the assignment. What am I doing wrong here?

You don't show how cmdlArgc and cmdlArgv are declared; it's surely in a header file, but what does it look like?.
Nothing outside of main.m will have access to those variables as they have been defined static, which leads me to wonder why you aren't getting linker errors. I have concluded that the declaration of the of cmdlArgc and cmdArgv is something like this:
int cmdlArgc;
const char** cmdlArgv;
rather than this:
extern int cmdlArgc;
extern const char** cmdlArgv;
So every implementation file that includes the header will get their own copy, which is why it's 0/NULL.
The solution is to drop the use of static in main.m and start using extern in the header.
However it's still an ugly pattern and I would think the very best solution is to rename main.m to main.mm and initialise CCommandLineArgs in main(), which is both clean and simple.

Related

When mixing C and C++ code, does main() need to be in the C++ part?

I have a C program that I need to interface with a C++ library (ROS). Normally, it's not too difficult to interface C code with C++ code with a wrapper using extern "C" and using the C++ compiler to link, but I've never had to do it where main was in the C portion.
The C++ FAQ indicates that this is a bad thing:
Here are some high points (though some compiler-vendors might not require all these; check with your compiler-vendor’s documentation):
You must use your C++ compiler when compiling main() (e.g., for static initialization)
But I see another source saying it should be okay these days:
At one time, most C++ compilers required that function main be compiled by the C++ compiler. That requirement is not common today, ...
Why would it matter whether main is in the C portion or the C++ portion? How much trouble would I be in if I try to link code where it's in the C portion using common linkers today (mainly GCC's and Clang's)?
One easy way to work around this is to rename your C main() and call it from a new C++ main()
As in:
// in ypur current C main module
int my_c_main(int argc, char* argv[]) /* renamed, was main() */
{
/* ... */
]
// in a c++ module...
int main(int argc, char* argv[])
{
extern "C" int my_c_main(int argc, char* argv[]);
// if your c main() requires environment variables passed in envp,
// You can allocate space for strings and an array here and pass
// the environment variables you'll need, as the third parameter
// to my_c_main(), or pass environ, if your system has
// it defined in unistd.h
return my_c_main(argc, argv);
}

Catch test framework issue: cannot use Catch::Session()

I get this error in a C++ file where I am writing some tests:
error: no member named 'Session' in namespace 'Catch'
testResult = Catch::Session().run(test_argc, test_argv);
~~~~~~~^
Looking at the catch.hpp single header file, I noticed that the code that should implement the Session() member function is greyed out, probably because of an #ifdef somewhere, which I cannot find.
Is there any macro to set to use the Session class?
Catch versions: 1.5.3 and 1.5.6.
Reference: https://github.com/philsquared/Catch/blob/master/docs/own-main.md
You're attempting to call the constructor of Catch::Session from a file where you're not defining your own main to execute. According to the documentation on defining your own main, there is supposed to be only one instance of Catch::Session:
Catch::Session session; // There must be exactly once instance
It's likely Catch is preventing construction of Catch::Session in translation units where it can't be used in a custom main definition (since that's where it's supposed to be used), to prevent exactly the mistake you've made from compiling.
Reference to https://github.com/catchorg/Catch2/blob/master/docs/own-main.md
You can only provide main in the same file you defined CATCH_CONFIG_RUNNER.
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
int main( int argc, char* argv[] ) {
// global setup...
int result = Catch::Session().run( argc, argv );
// global clean-up...
return result;
}

C++ What is my own file name?

I have a piece of C++ code that calls the system command.. I want to pass the file name of my own C++ executable to the system command.. anyone know how to do this?
So for example my C++ code is called "switch-5".. what I want to do is something like;
system("./script.sh switch-5");
Anyone have any clue?
Your executable name is the first argument passed in argv.
To test this just run:
int main(int argc, char **argv)
{
printf("My program name: '%s'\n", argv[0]);
return 0;
}
(I am assuming you know how to combine it with your script name to get the string to pass to system().)
argv[0] as passed to main is the name of your executable.
Store it in a global variable during app startup:
static char *selfname;
int main(int argc, char **argv)
{
selfname = argv[0];
// etc.
}
Beware, argv[0] contains exactly what was used to start the program, including relative or absolute path, for example: "./programname".

static main from static class?

I'm trying to figure out why this is not working. I want to do like in Java where main is a static function in a class but this is producing unresolved external symbol error:
static class MainClass
{
public:
static int _tmain(int argc, char* argv[])
{
return 0;
}
};
Why doesn't this work?
Thanks
C++ does not work like that.
You need main as a function:
int main(int argc,char* argv[])
{
//STUFF
}
Because _tmain is mangled in the binary with the class name MainClass in it, so multiple classes could have a function _tmain in them and not conflict. It's not got the same mangled name as ::_tmain is going to have.
I remember that with an earlier version of MSVC, it accepted the following without a linker error which ended up accidentally as a result of macro expansion in my code base once
namespace bar {
int main() { }
}
It apparently treated the name main specially and didn't mangle it or mangle it the same as ::main. But such a thing is not Standard conformant. Like in the class case, such a function is completely unrelated to the main function.
_tmain is called from CRT. You need to set in your linker an entry point to another function that will call MainClass::_tmain instead.
Because, in C++, you cannot put an entry point inside a class. This answer might help.
Why doesn't that work? Because it's not C++.
struct MainClass {
static int main(int argc, char** argv) {
return 0;
}
};
int main(int argc, char** argv) {
return MainClass::main(argc, argv);
}
It's not really C++, so much as the standard linker process which is looking for an export of a specific name (with C-style linkage). The specific export varies based on the compiler and executable type, but the format is specific for each type. For example, Windows GUI exe's have different entry points than console, and specific for ASCII or UNICODE. But the linker is always looking for a function with a specific link name, which is why a static member won't work.
You always need main() defined as a global function. This is where the program always starts in C++. You could simple call your static class function from main and pass on the variables if you really want to:
class MainClass
{
public:
static int _tmain(int argc, char* argv[])
{
return 0;
}
};
int main(int argc, char* argv[]) {
return MainClass::_tmain(argc, argv);
}

VC++: non-global old-style function declarations?

In Visual Studio 2003 using pure C, old-style function
declarations do not show as global member
i.e. void func(blah) int blah;{...}
This shows as a global member in the members dropdown:
void func(int blah)
{
...
}
This compiles, but old-style does not appear in the global
members dropdown:
void func(blah)
int blah;
{
...
}
I am trying to use the new 'Calling Graph' functionality to
analyse code, but as most of our legacy code uses the
old-style function parameters, those functions are not
recognized are not shown as Global Members, and therefore do
not appear in the 'Calling Graph'.
Is there any way to let the "call graph" analysis process
old-style function declarations correctly?
Maybe you want to consider to just change the old style function signatures. There shouldn't be any issues with that.
EDIT:
For an automatic conversion of your source files from old style syntax to ANSI-C style, take a look at the cproto tool. Maybe that could save you some time if you decide to go that direction.
This is an excerpt from the docs:
-f n
Set the style of generated function prototypes where n is a
number from 0 to 3. For example,
consider the function definition
main (argc, argv)
int argc;
char *argv[];
{
}
If the value is 0, then no prototypes are generated. When set to
1, the output is:
int main(/*int argc, char *argv[]*/);
For a value of 2, the output has the form:
int main(int /*argc*/, char */*argv*/[]);
The default value is 3. It produces the full function prototype:
int main(int argc, char *argv[]);
I'm not sure but maybe the engine uses regexs to trace routine signatures and the old C style isn't implemented.