Есть ли C ++, эквивалентный getcwd? - PullRequest
31 голосов
/ 04 февраля 2010

Я вижу C getcwd через: человек 3 cwd

Я подозреваю, что в C ++ есть похожий, который может вернуть мне std :: string.

Если так, как это называется и где я могу найти документацию?

Спасибо!

Ответы [ 8 ]

24 голосов
/ 05 февраля 2010

Хорошо, я отвечаю, даже если вы уже приняли ответ.

Еще лучший способ обернуть вызов 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();
21 голосов
/ 04 февраля 2010
Конструктор

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 () не определено.

12 голосов
/ 05 февраля 2010

Давайте попробуем переписать этот простой вызов 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());
        }
    }
}

Дело в том, что при переносе библиотечной функции в другую функцию вы должны предполагать, что все функциональные возможности должны быть доступны, потому что библиотека не знает, что будет вызывать ее. Поэтому вы должны обрабатывать ошибки, а не просто глотать их или надеяться, что они не произойдут.

Обычно лучше позволить клиентскому коду просто вызывать библиотечную функцию и устранять ошибку в этот момент - клиентскому коду, вероятно, не важно, почему произошла ошибка, и поэтому ему нужно только обработать случай «пройти / не пройти» , а не все коды ошибок.

5 голосов
/ 05 февраля 2010

Вам нужно просто написать небольшую обертку.

std::string getcwd_string( void ) {
   char buff[PATH_MAX];
   getcwd( buff, PATH_MAX );
   std::string cwd( buff );
   return cwd;
}
3 голосов
/ 30 октября 2013

Я использовал 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 ++.

3 голосов
/ 04 февраля 2010

Все функции C также являются функциями C ++. Если вам нужен std::string, просто создайте его из char*, который getcwd получает для вас.

1 голос
/ 15 июня 2017

Я также использовал boost :: filesystem , как указано в другом ответе выше. Я просто хотел добавить, что поскольку функция current_path () не возвращает std :: string, вам необходимо преобразовать ее.

Вот что я сделал:

std::string cwd = boost::filesystem::current_path().generic_string();
0 голосов
/ 07 июля 2017

Вы можете создать новую функцию, которую я бы предпочел вместо ссылки на библиотеку, такую ​​как boost (если вы еще этого не сделали).

 std::string getcwd()
 {
     char* buff;//automatically cleaned when it exits scope
     return std::string(getcwd(buff,255));
 }
...