Pergunta

Existe um método independente de plataforma e sistema de arquivos agnóstica para obter o caminho completo do diretório de onde um programa está sendo executado usando C / C ++? Não deve ser confundido com o diretório de trabalho atual. (Por favor, não sugerem bibliotecas menos que eles são queridos padrão como clib ou STL).

(Se não há nenhum método de plataforma / filesystem-agnóstico, sugestões que funcionam em Windows e Linux para sistemas de arquivos específicos são bem-vindos também.)

Foi útil?

Solução

código de aqui para obter o caminho completo para o aplicativo em execução:

Windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
    return -1;
else
    return bytes;

Linux:

char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;

Outras dicas

Se você buscar o diretório atual quando seu programa iniciado pela primeira vez, então você tem efetivamente o diretório seu programa foi iniciado a partir. Armazenar o valor em uma variável e se referem a ele mais tarde, em seu programa. Isso é diferente de o diretório que contém o atual arquivo executável programa . Não é necessariamente o mesmo diretório; se alguém executa o programa a partir de um prompt de comando, em seguida, o programa está sendo Executar diretório de trabalho atual do prompt de comando, mesmo que o arquivo de programa vive em outro lugar.

getcwd é uma função POSIX e apoiado fora da caixa por todas as plataformas compatíveis com POSIX. Você não teria que fazer nada especial (além de incliding os cabeçalhos corretos unistd.h em Unix e direct.h no Windows).

Como você está criando um programa em C que irá ligar com o padrão c biblioteca de tempo de execução que está ligado ao por todos os processos no sistema (especialmente exceções evitados trabalhada) e vai incluir esta função por padrão. A CRT nunca é considerado uma biblioteca externa, porque isso fornece a interface compatível com padrão básico para o sistema operacional.

No windows função getcwd foi preterido em favor de _getcwd. Eu acho que você poderia usá-lo desta forma.

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
 #endif

 char cCurrentPath[FILENAME_MAX];

 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
     {
     return errno;
     }

cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */

printf ("The current working directory is %s", cCurrentPath);

Esta é a partir do cplusplus fórum

No Windows:

#include <string>
#include <windows.h>

std::string getexepath()
{
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}

No Linux:

#include <string>
#include <limits.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
}

No HP-UX:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  struct pst_status ps;

  if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
    return std::string();

  if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
    return std::string();

  return std::string( result );
}

Se você quiser uma maneira padrão sem bibliotecas: Não. Todo o conceito de um diretório não está incluído no padrão

Se você concorda que alguma dependência (portátil) em um lib quase-padrão é bem: Use biblioteca de sistema de arquivos do Boost e pedir a initial_path () .

IMHO que é o mais perto que se pode chegar, com um bom karma (Boost é um conjunto de alta qualidade bem estabelecida de bibliotecas)

Sistema de Ficheiros TS é agora um padrão (e suportada por gcc 5,3 + e clang 3.9+), assim você pode usar current_path() função a partir dele :

Em gcc (5.3+) para incluir sistema de arquivos que você precisa para uso:

#include <experimental/filesystem>

e ligar seu código com a bandeira -lstdc++fs.

Se você quiser usar sistema de arquivos com o Microsoft Visual Studio, então ler este .

Eu sei que é muito tarde no dia para lançar uma resposta em um presente, mas eu achei que nenhuma das respostas eram tão útil para mim como a minha própria solução. Uma maneira muito simples para obter o caminho do seu CWD para a pasta bin é assim:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

Agora você pode apenas usar isso como uma base para o seu caminho relativo. Assim, por exemplo, eu tenho esta estrutura de diretórios:

main
  ----> test
  ----> src
  ----> bin

e eu quero compilar meu código-fonte para bin e escrever um log para testar posso apenas acrescentar esta linha ao meu código.

std::string pathToWrite = base + "/../test/test.log";

Eu tentei esta abordagem no Linux usando caminho completo, aliás, etc e ele funciona muito bem.

NOTA:

Se você estiver no Windows, você deve usar um '\' como separador de arquivo não '/'. Você terá que escapar isso também, por exemplo:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

Eu acho que isso deve funcionar, mas não testei, então comentário seria apreciada se funciona ou uma correção se não.

Não, não há nenhuma maneira padrão. Eu acredito que as normas C / C ++ nem sequer considerar a existência de diretórios (ou outras organizações do sistema de arquivos).

No Windows GetModuleFileName () irá retornar o caminho completo para o arquivo executável do processo atual quando o hModule parâmetro é definido como NULL . Eu não posso ajudar com o Linux.

Além disso, você deve esclarecer se deseja que o diretório atual ou o diretório que a imagem programa / reside executáveis. Tal como está a sua pergunta é um pouco ambíguo sobre este ponto.

Talvez concatenar o diretório de trabalho atual com o argv [0]? Eu não tenho certeza se isso iria funcionar no Windows, mas ele funciona em Linux.

Por exemplo:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
    char the_path[256];

    getcwd(the_path, 255);
    strcat(the_path, "/");
    strcat(the_path, argv[0]);

    printf("%s\n", the_path);

    return 0;
}

Quando executado, ele gera:

Jeremy @ Jeremy-desktop: ~ / Desktop $ ./test
/ Home / Jeremy / Desktop /./ teste

Você não pode usar argv [0] para o efeito, geralmente ele contém caminho completo para o executável, mas não nessesarily - processo poderia ser criado com valor arbitrário no campo.

Também lembre-se, o diretório atual eo diretório com o executável são duas coisas diferentes, de modo getcwd () não vai ajudá-lo a qualquer um.

No Windows uso GetModuleFileName (), no Linux ler / dev / proc / procID / .. arquivos.

No Windows a maneira mais simples é usar a função _get_pgmptr em stdlib.h para obter um ponteiro para uma string que representa o caminho absoluto para o executável, incluindo o nome executáveis.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe

Para Win32 GetCurrentDirectory deve fazer o truque .

Apenas a pilha tardiamente aqui, ...

não há uma solução padrão, porque as línguas são agnósticos de sistemas de arquivos subjacentes, assim como já foi dito, o conceito de um sistema de arquivos baseado em diretório está fora do escopo de C / C ++ idiomas.

Em cima disso, você não quer que o diretório de trabalho atual, mas o diretório o programa está sendo executado em, que deve levar em conta a forma como o programa chegou ao ponto onde ele é - ou seja, foi gerado como um novo processo através de um garfo , etc. Para obter o diretório de um programa está sendo executado em, como as soluções têm demonstrado, requer que você obter essa informação a partir das estruturas do sistema operacional em questão, que é a única autoridade sobre esta questão de controle de processo. Assim, por definição, seu uma solução OS específico.

Para o sistema do Windows no console, você pode usar o comando do sistema (dir). Eo console fornece informações sobre diretório e etc. Leia sobre o comando dir em cmd. Mas para Unix-like sistemas, eu não sei ... Se este comando é executado, leia comando bash. ls diretório não exibe ...

Exemplo:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
#include <windows.h>
using namespace std;

// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
    const unsigned long maxDir = 260;
    char currentDir[maxDir];
    GetCurrentDirectory(maxDir, currentDir);
    return string(currentDir);
}

O comando bash linux que progname irá relatar um caminho para programa.

Ainda que se pudesse emitir o qual comando de dentro de seu programa e direcionar a saída para um arquivo tmp eo programa posteriormente lê esse arquivo tmp, não vai dizer se esse programa é a execução. Ele só lhe diz onde um programa com esse nome está localizado.

O que é necessário é obter o seu número de ID do processo, e para analisar o caminho para o nome

No meu programa eu quero saber se o programa foi executado a partir do diretório bin do usuário ou de outro no caminho ou a partir de / usr / bin. / Usr / bin conteria a versão suportada. Meu sentimento é que no Linux não é a única solução que é portátil.

Por caminhos relativos, aqui está o que eu fiz. Estou ciente da idade esta pergunta, eu simplesmente querem contribuir com uma resposta mais simples que funciona na maioria dos casos:

Digamos que você tenha um caminho como este:

"path/to/file/folder"

Por alguma razão, executáveis ??Linux construídos feita em eclipse trabalho bem com isso. No entanto, o Windows fica muito confuso se for dado um caminho como este para trabalho com!

Como afirmado acima, existem várias maneiras de obter o caminho atual para o executável, mas o mais fácil achado maneira que eu trabalha um encanto na maioria dos casos é acrescentar isso à frente de seu caminho:

"./path/to/file/folder"

Basta adicionar "./" deverá fazê-lo resolvido! :) Então você pode começar a carregar a partir de qualquer diretório que você deseja, por isso, desde que seja com o executável em si.

EDIT: isto não vai funcionar se você tentar iniciar o executável a partir do código :: blocos se esse é o ambiente de desenvolvimento em uso, pois por alguma razão, Code :: Blocks não carrega direito material ...: D

EDIT2: Algumas coisas novas que tenho encontrado é que se você especificar um caminho estático como este em seu código (Assumindo Example.data é algo que você precisa de carga):

"resources/Example.data"

Se você, em seguida, iniciar o seu aplicativo a partir do diretório atual (ou no Windows, você fazer um atalho, e definir o dir trabalhando para o diretório app), em seguida, ele vai trabalhar assim. Tenha isso em mente ao depurar problemas relacionados à falta de caminhos de recursos / arquivo. (Especialmente em IDEs que definir o dir de trabalho errado ao lançar um exe construção do IDE)

Em plataformas POSIX, você pode usar getcwd () .

No Windows, você pode usar _getcwd () , como o uso de getcwd () foi substituído.

Para bibliotecas padrão, se impulso foram suficientes padrão para você, eu teria sugerido boost :: filesystem, mas eles parecem ter a normalização do caminho removida a proposta. Você pode ter que esperar até TR2 torna-se prontamente disponível para uma solução totalmente padrão.

Impulsione comporta initial_path() do Sistema de arquivo como getcwd() do POSIX, e nem faz o que quiser, por si só, mas acrescentando argv[0] para qualquer um deles deve fazê-lo.

Você pode notar que o resultado não é sempre bonito - você pode obter coisas como /foo/bar/../../baz/a.out ou /foo/bar//baz/a.out, mas eu acredito que ele sempre resulta em um caminho válido que dá nome ao arquivo executável (note que cortes consecutivos em um caminho são recolhidos para um).

I anteriormente escreveu uma solução usando envp (o terceiro argumento para main() que trabalhou no Linux, mas não parece viável no Windows, então estou essencialmente recomendando a mesma solução que alguém fez anteriormente, mas com a explicação adicional de por isso que é realmente correto, mesmo que os resultados não são bonitas.

A Minok mencionado, não existe tal funcionalidade especificado padrão C ini ou C ++ padrão. Este é considerado puramente recurso específico do sistema operacional e está especificado no padrão POSIX, por exemplo.

Thorsten79 tem dado boa sugestão, é biblioteca Boost.Filesystem. No entanto, pode ser inconveniente no caso de você não quer ter quaisquer dependências link-time em formato binário para o seu programa.

Uma boa alternativa Eu recomendaria é uma coleção de 100% cabeçalhos somente STLSoft C ++ Bibliotecas Matthew Wilson (autor de livros de leitura obrigatória sobre C ++) . Não é portátil fachada PlatformSTL dá acesso a específicas do sistema API: WinSTL para Windows e UnixSTL em Unix, por isso é solução portátil. Todos os elementos específicos do sistema são especificados com o uso de traços e políticas, por isso é estrutura extensível. Há biblioteca de sistema de arquivos desde que, é claro.

A solução de biblioteca (embora eu sei que isso não foi solicitado). Se acontecer de você usar Qt: QCoreApplication::applicationDirPath()

Use realpath() em stdlib.h assim:

char *working_dir_path = realpath(".", NULL);

Funciona com a partir de C ++ 11, utilizando o sistema de arquivos experimental, e C ++ 14 C ++ 17 bem usando sistema de arquivos oficial.

application.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

application.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top