Вот минимальный рабочий пример, описывающий мою текущую ситуацию. Файл main.cpp
#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, которое я хочу загрузить в переменную во внешнем файле. Есть ли способ сделать это без необходимости вызывать print_from_external_file () с argv [1]? Другими словами, может ли «а» автоматически быть присвоено значение «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
.час:
#include <iostream>
using namespace std;
int a;
//the rest goes unchanged
Если вы можете изменить файл, в котором определена переменная «a», поместите переменную в неанонимное пространство имен или определите экспортированный метод получения в том же файле (same1.cpp или same2.cpp ниже). В противном случае вы не сможете установить его так, как хотите.
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;
}
Я думаю, что вы ищете, это использование внешний ключевое слово.
Если вы объявите в своем основном a
как внешний переменная у вас должно быть все в порядке.
#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;
}
Если вы используете Windows,
namespace
{
int nArgs = 0;
int a = wtoi(CommandLineToArgvW(GetCommandLineW(), &nArgs)[0]);
}
Ради краткости я пропустил все проверки ошибок.
Да, ты можешь.
для целых чисел вы должны использовать std::atoi().
поэтому код становится:
int a = std::atoi(argv[1]);
Стандартная практика заключается в использовании 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;
}