Question

Here is a minimal working example describing my current situation. The file main.cpp

#include <iostream>
void print_from_external_file();

using namespace std;

int main( int argc, char* argv[])
{
    print_from_external_file();

    return 0;
}

The file containing print_from_external_file()

#include <iostream>
using namespace std;

namespace
{
    int a;
}

void print_from_external_file()
{
    cout << a << endl;
}

Here is my goal: I wish to run this program by command line like "test.exe 2". The integer 2 I want to be loaded into the variable a in the external file. Is there a way to accomplish this without having to call print_from_external_file() with argv[1]? In other words, can "a" be given the value "2" automatically?

Was it helpful?

Solution

You will have to name your namespace. Unnamed namespaces are tied to their translation units, so you will not be able to access the variable in it from another unit.

Your .cpp:

#include <iostream>
#include <stdlib.h>
#include "main.h"
void print_from_external_file();

using namespace std;
using ddd::a;

int main( int argc, char* argv[])
{
    a = atoi( argv[1] );
    print_from_external_file();

    return 0;
}

Your .h:

#include <iostream>
using namespace std;

namespace ddd
{
    int a;
}
using ddd::a;

void print_from_external_file()
{
    cout << a << endl;
}

Alternatively you can get rid of the namespace, and use extern int a in your .cpp file to get access to the variable:

.cpp

#include <iostream>
#include <stdlib.h>
#include "main.h"
void print_from_external_file();

using namespace std;
extern int a;
//the rest goes unchanged

.h:

#include <iostream>
using namespace std;

int a;
//the rest goes unchanged

OTHER TIPS

If you can change the file where the variable "a" is defined then put the variable to a non-anonymous namespace or define an exported getter in the same file (same1.cpp or same2.cpp below). Otherwise you won't be able to set it the way you want.

some1.cpp:

namespace {
   int a;
}
void set_a(int a_) { a = a_; }

some2.cpp:

namespace some {
   int a;
}

main.cpp:

#include <cstdlib>

namespace some {
  extern int a;
}

int main(int argc, char** argv) {
  assert(argc == 2);

  some::a = atoi(argv[1]);
  // or: set_a(atoi(argv[1]));
  return 0;
}

I think what you are looking for is the use of the extern keyword. If you declare in your main a as an extern variable you should be ok.

#include <iostream>
void print_from_external_file();

using namespace std;

extern int a;

int main( int argc, char* argv[])
{
   //set value of a
   a = atoi(argv[1]); //atoi is deprecated but is easier to use in an example

    print_from_external_file();

    return 0;
}

EDIT

In the second file you need to remove the namespace or specify a name for it. I tested using the following code for the second file and it worked as expected

#include <iostream>
using namespace std;

namespace
{
    int a;
}

void print_from_external_file()
{
    cout << a << endl;
}

EDIT 2: Code using namespace

File 1

#include <iostream>
void print_from_external_file();

using namespace std;

namespace TEST
{
    extern int a;
}

int main( int argc, char* argv[])
{
    //set value of a
    TEST::a = atoi(argv[1]); //atoi is deprecated but is easier to use in an example

    print_from_external_file();

    return 0;
}

File 2

#include <iostream>
using namespace std;

namespace TEST
{
    int a;
}

void print_from_external_file()
{
    cout << TEST::a << endl;
}

If you are using windows,

namespace
{
    int nArgs = 0;
    int a = wtoi(CommandLineToArgvW(GetCommandLineW(), &nArgs)[0]);
}

For the sake of brevity I skipped all error checking.

yes you can.

for integers you have to use std::atoi().

so the code becomes:

int a = std::atoi(argv[1]);

Standard practice is to use argv to access the command line arguments. You may find on some architectures that there are other way of doing this but they are not likely to be portable and there doesn't seem to be much reason here not to go with the standard practice. To read the value into an int you can either use strtol

long n = strtol( argv[1], NULL, 0 );

(note that I tend to prefer using strtol to atoi as you've a little more control over the inputs and the error handling - but not much)

You can also use streams as follows:

istringstream ss( argv[1] );
long n;
ss >> n;

Two things do concern me about what you're trying to do though: Firstly you want a variable value, set at runtime to be encapsulated within a function. Logically this will make your code less maintainable as there will be an invisible dependency between your function and an outside influence (a command line parameter) - so the deterministic properties of your function will have been compromised. Practically, this is going to make testing your function far more difficult - especially using automated unit testing as there will be no way of setting the value programatically prior to running it.

Secondly, as if to compound this, you are seeking to restrict scope of the a variable to compilation unit within the unnamed namespace. This has two undesirable effects. Firstly, no test harnesss or any other code is going to be able to see this variable so again from an automated UT standpoint, this is pretty bad. Secondly, a becomes effectively a 'global' within your compilation unit. Within functions in this compilation unit, it's going to be quite tricky to follow how and when a is used meaning a bit of a headache for anyone who maintains your code. I'll assume that you're not using multithreading which would really cause problems.

I'd be interested to know the reasons why you don't want to pass argv[1] into print_from_external_file() but I really think that this is the best thing to do. If you don't feel you can pass this variable either directly as a string or converted to an int, you could consider creating a command line parameters or configuration object which could be passed in:

configuration c( argc, argv ); // This contains the hard work of parsing the CL
print_from_external_file( c );

This hides most of the hard work of parsing the command line. Better still it allows you to add real meaning to the CL parameter. Let's say that the a variable represents a catalog number, the constructor of yourconfiguration class can simply do this:

configuration::configuration( int argc, char* argv[] )
{
    // ...
    catalogNo_ = strtol( argv[1], NULL, 0 );

and then if an accessor is added:

int configuration::get_catalog_no() const { return catalogNo_; }

then it becomes much more obvious in print_from_external_file() what we're doing:

void print_from_external_file( const configuration& c )
{
    cout << c.get_catalog_no() << endl;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top