Есть ли C++, эквивалентный getcwd?
Я вижу C's getcwd через: человек 3 CWD
Я подозреваю, что у C++ есть подобный, который мог бы вернуть мне std::string .
Если так, как это называется и где я могу найти документацию?
Спасибо!
8 ответов
Хорошо, я отвечаю, даже если вы уже приняли ответ.
Еще лучший способ, чем обернуть вызов getcwd, это использовать boost:: filesystem, где вы получите path
объект из current_path()
функция. Библиотека файловой системы Boost позволяет вам делать множество других полезных вещей, которые в противном случае вам пришлось бы выполнять много разборов строк, таких как проверка наличия файлов / каталогов, получение родительского пути, заполнение путей и так далее. Проверьте это, это также переносимо - что, вероятно, не будет много кода для разбора строк, который можно было бы использовать в противном случае.
Обновление (2016): Файловая система была опубликована в виде технической спецификации в 2015 году на основе Boost Filesystem v3. Это означает, что он может быть доступен уже с вашим компилятором (например, Visual Studio 2015). Мне также кажется вероятным, что он станет частью будущего стандарта C++ (я бы предположил, что C++17, но я не знаю о текущем состоянии).
Обновление (2017): библиотека файловой системы была объединена с ISO C++ в C++17, для
std::filesystem::current_path();
std::string
конструктор может смело char*
в качестве параметра. Удивительно, но есть и версия для Windows.
Изменить: на самом деле это немного сложнее:
std::string get_working_path()
{
char temp[MAXPATHLEN];
return ( getcwd(temp, sizeof(temp)) ? std::string( temp ) : std::string("") );
}
С памятью проблем нет - temp является стековым буфером, а конструктор std::string делает копию. Возможно, вы могли бы сделать это за один раз, но я не думаю, что стандарт будет гарантировать это.
О распределении памяти через POSIX:
Функция getcwd() должна поместить абсолютный путь текущего рабочего каталога в массив, на который указывает buf, и вернуть buf. Путь, скопированный в массив, не должен содержать компонентов, которые являются символическими ссылками. Аргумент size - это размер в байтах массива символов, на который указывает аргумент buf. Если buf - нулевой указатель, поведение getcwd() не определено.
Давайте попробуем переписать этот простой вызов C как C++:
std::string get_working_path()
{
char temp [ PATH_MAX ];
if ( getcwd(temp, PATH_MAX) != 0)
return std::string ( temp );
int error = errno;
switch ( error ) {
// EINVAL can't happen - size argument > 0
// PATH_MAX includes the terminating nul,
// so ERANGE should not be returned
case EACCES:
throw std::runtime_error("Access denied");
case ENOMEM:
// I'm not sure whether this can happen or not
throw std::runtime_error("Insufficient storage");
default: {
std::ostringstream str;
str << "Unrecognised error" << error;
throw std::runtime_error(str.str());
}
}
}
Дело в том, что при переносе библиотечной функции в другую функцию вы должны предполагать, что все функциональные возможности должны быть доступны, потому что библиотека не знает, что будет вызывать ее. Таким образом, вы должны обрабатывать ошибки, а не просто глотать их или надеяться, что они не произойдут.
Обычно лучше позволить клиентскому коду просто вызывать библиотечную функцию и иметь дело с ошибкой в этот момент - клиентский код, вероятно, не заботится о том, почему произошла ошибка, и поэтому должен обрабатывать только случай "пройти / не пройти", а не все коды ошибок.
Вам нужно просто написать небольшую обертку.
std::string getcwd_string( void ) {
char buff[PATH_MAX];
getcwd( buff, PATH_MAX );
std::string cwd( buff );
return cwd;
}
Я использовал getcwd()
в C следующим образом:
char * cwd;
cwd = (char*) malloc( FILENAME_MAX * sizeof(char) );
getcwd(cwd,FILENAME_MAX);
Требуется заголовочный файл stdio.h
, Когда я использую компилятор C, он работает отлично.
Если я скомпилирую точно такой же код с использованием компилятора C++, он выдаст следующее сообщение об ошибке:
identifier "getcwd" is undefined
Тогда я включил unistd.h
и скомпилирован с компилятором C++. На этот раз все работает. Когда я вернулся к компилятору C, он все еще работает!
Пока вы включаете оба stdio.h
а также unistd.h
приведенный выше код работает для компиляторов C и C++.
Все функции C также являются функциями C++. Если вам нужно std::string
Просто создайте один из char*
что getcwd получает для вас.
Я также использовал boost::filesystem, как указано в другом ответе выше. Я просто хотел добавить, что, поскольку функция current_path() не возвращает std::string, вам необходимо преобразовать ее.
Вот что я сделал:
std::string cwd = boost::filesystem::current_path().generic_string();
Вы можете создать новую функцию, которую я бы предпочел вместо ссылки на библиотеку, такую как boost(если вы еще не сделали этого).
std::string getcwd()
{
char* buff;//automatically cleaned when it exits scope
return std::string(getcwd(buff,255));
}