2012-10-31 118 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