Есть ли 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));
 }
Другие вопросы по тегам