2012-10-31 87 views
1

这是一个描述我目前情况的最小实例。该文件main.cpp中使用argv设置变量

#include <iostream> 
void print_from_external_file(); 

using namespace std; 

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

    return 0; 
} 

含文件print_from_external_file()

#include <iostream> 
using namespace std; 

namespace 
{ 
    int a; 
} 

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

这是我的目标:我希望通过运行命令行这一计划,如 “TEST.EXE 2”。我想要将整数2加载到外部文件中的变量a中。有没有办法做到这一点,而不必与argv [1]调用print_from_external_file()?换句话说,“a”能自动给出值“2”吗?

回答

2

你将不得不命名你的命名空间。未命名的命名空间绑定到它们的翻译单元,因此您将无法从其他单元访问它中的变量。

您的.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; 
} 

您的.h:

#include <iostream> 
using namespace std; 

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

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

或者你可以摆脱命名空间,并使用extern int a在你的.cpp文件,以获得进入变量:

的.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 
2

如果您可以更改定义变量“a”的文件,请将该变量放在非匿名命名空间中或在同一文件(same1.cpp或same2.cpp中)中定义导出的getter。否则,你将无法按照你想要的方式设置它。

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; 
} 
+1

这是假设a被定义在与main相同的范围。在我的MWE中情况并非如此。 – BillyJean

0

当然可以。

你必须使用std::atoi().

整数所以代码变成:

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

如果您使用的是Windows,

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

为简便起见,我跳过所有的错误检查。

+0

对不起意思是1而不是0 - wtoi(CommandLineToArgvW(GetCommandLineW(),&nArgs)[1]); – nanda

1

我想你正在寻找的是使用的extern关键字。 如果您在主a中声明为extern变量,您应该可以。

#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; 
} 

编辑

在您需要删除的命名空间或为其指定一个名称的第二个文件。 我测试使用下面的代码的第二个文件和它的工作如预期

#include <iostream> 
using namespace std; 

namespace 
{ 
    int a; 
} 

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

编辑2:使用代码命名空间

文件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; 
} 

文件2

#include <iostream> 
using namespace std; 

namespace TEST 
{ 
    int a; 
} 

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

这不能用在OP案例中,因为'a'位于未命名的名称空间内。 – SingerOfTheFall

+0

您的评论与我的编辑:) –

+0

这将不会编译:'../Test/main.cpp:12:4:错误:引用'a'是不明确的 ../Test/main.cpp:7: 12:错误:候选人是:int a ../Test/main.h:6:6:error:int {anonymous} :: a' – SingerOfTheFall

0

标准做法是使用argv来访问命令行参数。您可能会发现在某些体系结构中还有其他方法可以做到这一点,但它们不太可能是可移植的,在这里似乎没有太多理由不遵循标准惯例。要读取值到一个int您可以使用strtol

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

(请注意,我倾向于使用strtol因为你已经在投入多一点控制和错误处理更喜欢atoi - 但不是很多)

您也可以使用流如下:

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

两个事情并关心我你正在试图做什么,虽然:首先你想要的变量值,设置在运行时函数被封装。从逻辑上讲,这会使你的代码不易维护,因为你的函数和一个外部影响(一个命令行参数)之间会有一个不可见的依赖关系 - 所以你的函数的确定性属性会受到影响。实际上,这会让测试你的功能变得更加困难 - 尤其是使用自动化单元测试,因为在运行之前,没有办法设置该值。其次,如果要复合这一点,您正在寻求将a变量的范围限制为未命名名称空间内的编译单元。这有两个不良影响。首先,没有任何测试工具或任何其他代码能够从自动UT的角度再次看到这个变量,这是非常糟糕的。其次,a在您的编译单元中成为有效的“全局”。在这个编译单元的函数中,使用a的方式和时间会非常棘手,这对维护你的代码的任何人来说都有点头痛。我会假设你没有使用多线程,这真的会导致问题。

我想知道为什么你不想通过argv[1]print_from_external_file()的原因,但我真的认为这是最好的事情。如果你不觉得你可以直接通过这个变量作为字符串或转换为int,你可以考虑创建可能在传递一个命令行参数或配置对象:

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

这隐藏了大部分的解析命令行的努力工作。更好的是它可以让你给CL参数增加真正的含义。比方说,在a变量表示目录号,您configuration类的构造函数可以简单地这样做:

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

,然后如果访问添加:

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

则变得更加明显在print_from_external_file()我们在做什么:

void print_from_external_file(const configuration& c) 
{ 
    cout << c.get_catalog_no() << endl; 
} 
+0

感谢您的详细答案。我试图避免将a​​rgv [1]传递给该函数的原因是因为我的程序已经生成 - 并且需要很长时间才能再次完成此更改。更改命名空间是一个更快的解决方案,但据我了解,它带有一个价格。 – BillyJean

+1

@ niles_1710373:理解。一种可能性可能是将该值设置为环境变量,并使用'getenv()'在需要的地方读取它,但这涉及与上述相同的技术债务。如果是我,我只会咬下子弹来做。您可能会发现,不会花费您想象的时间,并且根据应用程序的保质期,通过保持设计的简单性和可读性,几乎肯定可以节省将来的维护时间(以及您的声誉!)。 –

+1

谢谢你,总是很好的获得专业意见 – BillyJean