निष्पादन योग्य का मार्ग प्राप्त करें


114

मुझे पता है कि यह सवाल पहले भी पूछा जा चुका है, लेकिन मैंने अभी भी एक संतोषजनक जवाब नहीं देखा है, या एक निश्चित "नहीं, यह नहीं किया जा सकता है", इसलिए मैं फिर से पूछूंगा!

मैं केवल इतना करना चाहता हूं कि वर्तमान में चल रहे निष्पादन के लिए रास्ता मिल जाए, या तो एक निरपेक्ष पथ के रूप में या जहां निष्पादन योग्य को एक मंच से स्वतंत्र रूप में लागू किया जाता है। मैं हालांकि बढ़ावा देता हूं :: filesystem :: initial_path मेरी परेशानियों का जवाब था, लेकिन यह केवल प्रश्न के 'प्लेटफ़ॉर्म-इंडिपेंडेंट' हिस्से को संभालने के लिए लगता है - यह अभी भी उस पथ को वापस लौटाता है जहां से आवेदन को लागू किया गया था।

थोड़ी सी पृष्ठभूमि के लिए, यह ओग्रे का उपयोग करने वाला एक गेम है, जिसे मैं बहुत नींद का उपयोग करके प्रोफ़ाइल करने की कोशिश कर रहा हूं, जो अपनी निर्देशिका से निष्पादन योग्य लक्ष्य को चलाता है, इसलिए निश्चित रूप से लोड पर गेम को कोई कॉन्फ़िगरेशन फ़ाइलें नहीं मिलती हैं और तुरंत क्रैश हो जाता है। । मैं इसे कॉन्फ़िगरेशन फ़ाइलों के लिए एक निरपेक्ष पथ पास करने में सक्षम होना चाहता हूं, जो मुझे पता है कि निष्पादन योग्य के साथ हमेशा रहेगा। विजुअल स्टूडियो में डिबगिंग के लिए भी यही होता है - मैं काम करने वाली डायरेक्टरी को सेट किए बिना $ (टारगेटपैथ) चलाना चाहता हूं।



9
ध्यान दें कि उत्तर की अनुपस्थिति को साबित करना असंभव है, इसलिए आपको एक निश्चित संख्या नहीं मिल सकती है । मैं आपको एक आधिकारिक सं। देने के लिए खुश हूँ :)
MSalters


" लोड पर गेम को कोई कॉन्फ़िगरेशन फ़ाइल नहीं मिलती है आदि " इसलिए गेम वर्तमान निर्देशिका पर कॉन्फ़िगरेशन फ़ाइलों की खोज करता है? यह एक बुरा विचार है, और संभवतः एक सुरक्षा भेद्यता है। कॉन्फ़िगरेशन फ़ाइलों को एक मानक स्थान में संग्रहीत किया जाना चाहिए।
जिज्ञासु

1
मैंने यहाँ एक संबंधित प्रश्न का उत्तर पोस्ट किया है जो आपके उत्तर देता है, बूस्ट का उपयोग कर प्लेटफार्मों पर काम कर रहा है
jtbr

जवाबों:


86

कोई क्रॉस प्लेटफ़ॉर्म रास्ता नहीं है जो मुझे पता है।

लिनक्स के लिए: रीडलिंक / proc / self / exe

विंडोज: GetModuleFileName


9
प्लेटफॉर्म की स्वतंत्रता केवल प्लेटफॉर्म की निर्भरता को छुपाने का मामला है। इस मामले में पूर्वनिर्धारित OS मैक्रो का उपयोग करते हुए विधि का चयन करने के लिए predef.sourceforge.net/preos.html पर विस्तृत विवरण सीधा है।
क्लिफोर्ड

4
तो क्या यह वही है जो हर कोई तब करता है जब वे C ++ में निष्पादन योग्य मार्ग खोजना चाहते हैं? मैं उम्मीद कर रहा था कि कुछ सरल-सा लग रहा होगा क्योंकि यह पहले से ही बढ़ावा देने वाली लाइब्रेरी में लागू होगा।
बेन हाइमर 19

2
@ कुरसीगुई मुझे यकीन नहीं है कि मैं आपको समझता हूं; मुझे पूरा यकीन है कि इस सवाल का पूरा बिंदु :)
बेन हाइमर

6
@curiousguy: आप ऐसा करना चाहते हैं, उदाहरण के लिए, आपका प्रोग्राम उपयोगकर्ता के चयन की निर्देशिका में स्थापित हो सकता है। आपको किसी भी तरह
ग्रेफेड

1
@ डक क्या आप अपने उत्तर को मेरी लीबी के लिंक के साथ अपडेट करेंगे? मेरी टिप्पणी सूची में दफन है।
ग्रेगरी पॉक्सोज

35

बढ़ावा :: dll :: program_location समारोह चल रहा निष्पादन योग्य है कि मैं के बारे में पता के रास्ते होने का सबसे अच्छा क्रॉस प्लेटफॉर्म तरीकों में से एक है। DLL लाइब्रेरी को संस्करण 1.61.0 में Boost में जोड़ा गया था।

निम्नलिखित मेरा समाधान है। मैंने इसे विंडोज, मैक ओएस एक्स, सोलारिस, फ्री बीएसडी और जीएनयू / लिनक्स पर परीक्षण किया है।

इसके लिए बूस्ट 1.55.0 या उससे अधिक की आवश्यकता होती है । यह का उपयोग करता है Boost.Filesystem पुस्तकालय सीधे और Boost.Locale पुस्तकालय और Boost.System पुस्तकालय परोक्ष रूप से।

src / executable_path.cpp

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/predef.h>
#include <boost/version.hpp>
#include <boost/tokenizer.hpp>

#if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0))
#  include <boost/process.hpp>
#endif

#if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS)
#  include <Windows.h>
#endif

#include <boost/executable_path.hpp>
#include <boost/detail/executable_path_internals.hpp>

namespace boost {

#if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS)

std::string executable_path(const char* argv0)
{
  typedef std::vector<char> char_vector;
  typedef std::vector<char>::size_type size_type;
  char_vector buf(1024, 0);
  size_type size = buf.size();
  bool havePath = false;
  bool shouldContinue = true;
  do
  {
    DWORD result = GetModuleFileNameA(nullptr, &buf[0], size);
    DWORD lastError = GetLastError();
    if (result == 0)
    {
      shouldContinue = false;
    }
    else if (result < size)
    {
      havePath = true;
      shouldContinue = false;
    }
    else if (
      result == size
      && (lastError == ERROR_INSUFFICIENT_BUFFER || lastError == ERROR_SUCCESS)
      )
    {
      size *= 2;
      buf.resize(size);
    }
    else
    {
      shouldContinue = false;
    }
  } while (shouldContinue);
  if (!havePath)
  {
    return detail::executable_path_fallback(argv0);
  }
  // On Microsoft Windows, there is no need to call boost::filesystem::canonical or
  // boost::filesystem::path::make_preferred. The path returned by GetModuleFileNameA
  // is the one we want.
  std::string ret = &buf[0];
  return ret;
}

#elif (BOOST_OS_MACOS)

#  include <mach-o/dyld.h>

std::string executable_path(const char* argv0)
{
  typedef std::vector<char> char_vector;
  char_vector buf(1024, 0);
  uint32_t size = static_cast<uint32_t>(buf.size());
  bool havePath = false;
  bool shouldContinue = true;
  do
  {
    int result = _NSGetExecutablePath(&buf[0], &size);
    if (result == -1)
    {
      buf.resize(size + 1);
      std::fill(std::begin(buf), std::end(buf), 0);
    }
    else
    {
      shouldContinue = false;
      if (buf.at(0) != 0)
      {
        havePath = true;
      }
    }
  } while (shouldContinue);
  if (!havePath)
  {
    return detail::executable_path_fallback(argv0);
  }
  std::string path(&buf[0], size);
  boost::system::error_code ec;
  boost::filesystem::path p(
    boost::filesystem::canonical(path, boost::filesystem::current_path(), ec));
  if (ec.value() == boost::system::errc::success)
  {
    return p.make_preferred().string();
  }
  return detail::executable_path_fallback(argv0);
}

#elif (BOOST_OS_SOLARIS)

#  include <stdlib.h>

std::string executable_path(const char* argv0)
{
  std::string ret = getexecname();
  if (ret.empty())
  {
    return detail::executable_path_fallback(argv0);
  }
  boost::filesystem::path p(ret);
  if (!p.has_root_directory())
  {
    boost::system::error_code ec;
    p = boost::filesystem::canonical(
      p, boost::filesystem::current_path(), ec);
    if (ec.value() != boost::system::errc::success)
    {
      return detail::executable_path_fallback(argv0);
    }
    ret = p.make_preferred().string();
  }
  return ret;
}

#elif (BOOST_OS_BSD)

#  include <sys/sysctl.h>

std::string executable_path(const char* argv0)
{
  typedef std::vector<char> char_vector;
  int mib[4]{0};
  size_t size;
  mib[0] = CTL_KERN;
  mib[1] = KERN_PROC;
  mib[2] = KERN_PROC_PATHNAME;
  mib[3] = -1;
  int result = sysctl(mib, 4, nullptr, &size, nullptr, 0);
  if (-1 == result)
  {
    return detail::executable_path_fallback(argv0);
  }
  char_vector buf(size + 1, 0);
  result = sysctl(mib, 4, &buf[0], &size, nullptr, 0);
  if (-1 == result)
  {
    return detail::executable_path_fallback(argv0);
  }
  std::string path(&buf[0], size);
  boost::system::error_code ec;
  boost::filesystem::path p(
    boost::filesystem::canonical(
      path, boost::filesystem::current_path(), ec));
  if (ec.value() == boost::system::errc::success)
  {
    return p.make_preferred().string();
  }
  return detail::executable_path_fallback(argv0);
}

#elif (BOOST_OS_LINUX)

#  include <unistd.h>

std::string executable_path(const char *argv0)
{
  typedef std::vector<char> char_vector;
  typedef std::vector<char>::size_type size_type;
  char_vector buf(1024, 0);
  size_type size = buf.size();
  bool havePath = false;
  bool shouldContinue = true;
  do
  {
    ssize_t result = readlink("/proc/self/exe", &buf[0], size);
    if (result < 0)
    {
      shouldContinue = false;
    }
    else if (static_cast<size_type>(result) < size)
    {
      havePath = true;
      shouldContinue = false;
      size = result;
    }
    else
    {
      size *= 2;
      buf.resize(size);
      std::fill(std::begin(buf), std::end(buf), 0);
    }
  } while (shouldContinue);
  if (!havePath)
  {
    return detail::executable_path_fallback(argv0);
  }
  std::string path(&buf[0], size);
  boost::system::error_code ec;
  boost::filesystem::path p(
    boost::filesystem::canonical(
      path, boost::filesystem::current_path(), ec));
  if (ec.value() == boost::system::errc::success)
  {
    return p.make_preferred().string();
  }
  return detail::executable_path_fallback(argv0);
}

#else

std::string executable_path(const char *argv0)
{
  return detail::executable_path_fallback(argv0);
}

#endif

}

src / विस्तार / executable_path_internals.cpp

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/predef.h>
#include <boost/version.hpp>
#include <boost/tokenizer.hpp>

#if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0))
#  include <boost/process.hpp>
#endif

#if (BOOST_OS_CYGWIN || BOOST_OS_WINDOWS)
#  include <Windows.h>
#endif

#include <boost/executable_path.hpp>
#include <boost/detail/executable_path_internals.hpp>

namespace boost {
namespace detail {

std::string GetEnv(const std::string& varName)
{
  if (varName.empty()) return "";
#if (BOOST_OS_BSD || BOOST_OS_CYGWIN || BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_SOLARIS)
  char* value = std::getenv(varName.c_str());
  if (!value) return "";
  return value;
#elif (BOOST_OS_WINDOWS)
  typedef std::vector<char> char_vector;
  typedef std::vector<char>::size_type size_type;
  char_vector value(8192, 0);
  size_type size = value.size();
  bool haveValue = false;
  bool shouldContinue = true;
  do
  {
    DWORD result = GetEnvironmentVariableA(varName.c_str(), &value[0], size);
    if (result == 0)
    {
      shouldContinue = false;
    }
    else if (result < size)
    {
      haveValue = true;
      shouldContinue = false;
    }
    else
    {
      size *= 2;
      value.resize(size);
    }
  } while (shouldContinue);
  std::string ret;
  if (haveValue)
  {
    ret = &value[0];
  }
  return ret;
#else
  return "";
#endif
}

bool GetDirectoryListFromDelimitedString(
  const std::string& str,
  std::vector<std::string>& dirs)
{
  typedef boost::char_separator<char> char_separator_type;
  typedef boost::tokenizer<
    boost::char_separator<char>, std::string::const_iterator,
    std::string> tokenizer_type;
  dirs.clear();
  if (str.empty())
  {
    return false;
  }
#if (BOOST_OS_WINDOWS)
  const std::string os_pathsep(";");
#else
  const std::string os_pathsep(":");
#endif
  char_separator_type pathSep(os_pathsep.c_str());
  tokenizer_type strTok(str, pathSep);
  typename tokenizer_type::iterator strIt;
  typename tokenizer_type::iterator strEndIt = strTok.end();
  for (strIt = strTok.begin(); strIt != strEndIt; ++strIt)
  {
    dirs.push_back(*strIt);
  }
  if (dirs.empty())
  {
    return false;
  }
  return true;
}

std::string search_path(const std::string& file)
{
  if (file.empty()) return "";
  std::string ret;
#if (BOOST_VERSION > BOOST_VERSION_NUMBER(1,64,0))
  {
    namespace bp = boost::process;
    boost::filesystem::path p = bp::search_path(file);
    ret = p.make_preferred().string();
  }
#endif
  if (!ret.empty()) return ret;
  // Drat! I have to do it the hard way.
  std::string pathEnvVar = GetEnv("PATH");
  if (pathEnvVar.empty()) return "";
  std::vector<std::string> pathDirs;
  bool getDirList = GetDirectoryListFromDelimitedString(pathEnvVar, pathDirs);
  if (!getDirList) return "";
  std::vector<std::string>::const_iterator it = pathDirs.cbegin();
  std::vector<std::string>::const_iterator itEnd = pathDirs.cend();
  for ( ; it != itEnd; ++it)
  {
    boost::filesystem::path p(*it);
    p /= file;
    if (boost::filesystem::exists(p) && boost::filesystem::is_regular_file(p))
    {
      return p.make_preferred().string();
    }
  }
  return "";
}

std::string executable_path_fallback(const char *argv0)
{
  if (argv0 == nullptr) return "";
  if (argv0[0] == 0) return "";
#if (BOOST_OS_WINDOWS)
  const std::string os_sep("\\");
#else
  const std::string os_sep("/");
#endif
  if (strstr(argv0, os_sep.c_str()) != nullptr)
  {
    boost::system::error_code ec;
    boost::filesystem::path p(
      boost::filesystem::canonical(
        argv0, boost::filesystem::current_path(), ec));
    if (ec.value() == boost::system::errc::success)
    {
      return p.make_preferred().string();
    }
  }
  std::string ret = search_path(argv0);
  if (!ret.empty())
  {
    return ret;
  }
  boost::system::error_code ec;
  boost::filesystem::path p(
    boost::filesystem::canonical(
      argv0, boost::filesystem::current_path(), ec));
  if (ec.value() == boost::system::errc::success)
  {
    ret = p.make_preferred().string();
  }
  return ret;
}

}
}

शामिल / बढ़ावा / executable_path.hpp

#ifndef BOOST_EXECUTABLE_PATH_HPP_
#define BOOST_EXECUTABLE_PATH_HPP_

#pragma once

#include <string>

namespace boost {
std::string executable_path(const char * argv0);
}

#endif // BOOST_EXECUTABLE_PATH_HPP_

शामिल / बढ़ावा / विस्तार / executable_path_internals.hpp

#ifndef BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_
#define BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_

#pragma once

#include <string>
#include <vector>

namespace boost {
namespace detail {
std::string GetEnv(const std::string& varName);
bool GetDirectoryListFromDelimitedString(
    const std::string& str,
    std::vector<std::string>& dirs);
std::string search_path(const std::string& file);
std::string executable_path_fallback(const char * argv0);
}
}

#endif // BOOST_DETAIL_EXECUTABLE_PATH_INTERNALS_HPP_

मेरे पास एक पूर्ण प्रोजेक्ट है, जिसमें एक परीक्षण एप्लिकेशन और सीमेक शामिल हैं जो SnKOpen - / cpp / निष्पादन योग्य_पथ / ट्रंक पर उपलब्ध फाइलों का निर्माण करते हैं । यह संस्करण मेरे द्वारा दिए गए संस्करण की तुलना में अधिक पूर्ण है। यह अधिक प्लेटफार्मों का भी समर्थन करता है।

मैंने निम्नलिखित चार परिदृश्यों में सभी समर्थित ऑपरेटिंग सिस्टम पर एप्लिकेशन का परीक्षण किया है।

  1. सापेक्ष पथ, वर्तमान निर्देशिका में निष्पादन योग्य: यानी ./executable_path_test
  2. सापेक्ष पथ, किसी अन्य निर्देशिका में निष्पादन योग्य: यानी ./build/executable_path_test
  3. पूर्ण पथ: यानी / कुछ / dir / निष्पादन योग्य_पथ_तम
  4. पथ में निष्पादन योग्य, केवल फ़ाइल नाम: यानी निष्पादन योग्य_पथ_स्टेस्ट

सभी चार परिदृश्यों में, निष्पादन योग्य_पथ और निष्पादन योग्य_पथ_फॉलबैक फ़ंक्शन दोनों कार्य करते हैं और समान परिणाम लौटाते हैं।

टिप्पणियाँ

यह इस प्रश्न का एक अद्यतन उत्तर है। मैंने उपयोगकर्ता टिप्पणियों और सुझावों को ध्यान में रखते हुए उत्तर को अपडेट किया। मैंने अपने एसवीएन रिपोजिटरी में एक परियोजना के लिए एक लिंक भी जोड़ा।


1
यह उचित कमियों के साथ एक बहुत ही पूर्ण समाधान की तरह दिखता है। +1! एक प्रश्न, हालांकि: क्या यह निश्चित चार [1024] बफ़र्स को वेक्टर <char> जैसी किसी चीज़ के साथ बदलने के लिए समझ में आता है जो कि पथ को प्रारंभिक आकार से अधिक होने पर आकार दिया जा सकता है?
डैनियल वुल्फ

हाँ। यह एक उत्कृष्ट सुझाव है। बेशक कुछ अतिरिक्त बदलाव करने की आवश्यकता होगी जैसे कि त्रुटियों की जाँच, बफर का आकार बदलना, और फिर से प्रयास करना।
बेन कुंजी

1
मुझे लगता है कि गिरावट सही नहीं है। argv[0]केवल निष्पादन योग्य नाम भी हो सकता है, इस स्थिति में PATH* निक्स सिस्टम पर इसे खोजना आवश्यक होगा ।
माइकल गोरी

1
मैंने इसका उपयोग करने की कोशिश की। लेकिन इसे बढ़ावा देने की जरूरत है, सही? मुझे लगा कि
मैनटेटा

1
आपने मुझे "बढ़ावा :: dll :: program_location"
थॉमस

31

इस तरह से बढ़ावा + argv का उपयोग करता है। आपने उल्लेख किया कि यह क्रॉस प्लेटफॉर्म नहीं हो सकता है क्योंकि इसमें निष्पादन योग्य नाम शामिल हो सकता है या नहीं भी हो सकता है। ठीक है कि निम्नलिखित कोड के आसपास काम करना चाहिए।

#include <boost/filesystem/operations.hpp>

#include <boost/filesystem/path.hpp>

#include <iostream>

namespace fs = boost::filesystem;


int main(int argc,char** argv)
{
    fs::path full_path( fs::initial_path<fs::path>() );

    full_path = fs::system_complete( fs::path( argv[0] ) );

    std::cout << full_path << std::endl;

    //Without file name
    std::cout << full_path.stem() << std::endl;
    //std::cout << fs::basename(full_path) << std::endl;

    return 0;
}

निम्न कोड को वर्तमान कार्यशील निर्देशिका मिलती है जो आपको आवश्यकता हो सकती है

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <iostream>

namespace fs = boost::filesystem;


int main(int argc,char** argv)
{
    //current working directory
    fs::path full_path( fs::current_path<fs::path>() );

    std::cout << full_path << std::endl;

    std::cout << full_path.stem() << std::endl;
    //std::cout << fs::basepath(full_path) << std::endl;

    return 0;
}

नोट बस महसूस basename(किया गया था कि ) पदावनत हो गया था इसलिए स्विच करना पड़ा.stem()


स्टेम मुझे सिर्फ निष्पादन योग्य ऋण देने के लिए लगता है पथ और विस्तार विंडोज पर, लेकिन यह एक मामूली बात है। मुझे पता है कि यह कैसे काम करता है argv [0] संभवतः गलत है? यह मेरे लिए विंडोज पर परीक्षण का काम करता है, लेकिन फिर argv [0] को वास्तव में निष्पादन योग्य के पूर्ण मार्ग के रूप में पारित किया जा रहा है, जो system_complete के काम को बहुत आसान बनाता है :)
बेन

1
नहीं - उसे कार्यशील निर्देशिका की आवश्यकता नहीं है। और कोई argv मदद नहीं करता है। जब आप argv में केवल निष्पादन योग्य नाम होते हैं तो आप क्या करते हैं ? क्या करें, जब प्रोग्राम को एक सिमलिंक के माध्यम से लागू किया गया था?
इचथियो

4
"// फ़ाइल नाम के बिना" - आप चाहते हैं .parent_path(), नहीं .stem(), नहीं?
क्लाउडीयू

2
यह मेरे प्लेटफ़ॉर्म (macOS El Capitan) पर काम नहीं करता है। मुझे इसके बजाय वर्तमान वर्किंग डायरेक्टरी मिलती है। इसके अलावा, जैसा @Claudiuकि कहा गया है, मुझे लगता है कि यह होना चाहिए .parent_path()
samvv

20

मैं लिनक्स के बारे में निश्चित नहीं हूं, लेकिन विंडोज के लिए यह कोशिश करता हूं:

#include <windows.h>
#include <iostream>

using namespace std ;

int main()
{
     char ownPth[MAX_PATH]; 

     // When NULL is passed to GetModuleHandle, the handle of the exe itself is returned
     HMODULE hModule = GetModuleHandle(NULL);
     if (hModule != NULL)
     {
         // Use GetModuleFileName() with module handle to get the path
         GetModuleFileName(hModule, ownPth, (sizeof(ownPth))); 
         cout << ownPth << endl ;
         system("PAUSE");
         return 0;
     }
     else
     {
         cout << "Module handle is NULL" << endl ;
         system("PAUSE");
         return 0;
     }
}

3
ध्यान दें कि एक का उपयोग करना चाहिए WCHAR ownPth.., #ifdef UNICODEइस घटना के चारों ओर लिपटे हुए हैं जो एक यूनिकोड समर्थन के साथ संकलित करता है। यदि नहीं, तो दिए गए कोड का उपयोग करें।
Dr1Ku

1
सिर्फ रिकॉर्ड के लिए मैं सिर्फ एक मज़ेदार मामला कर रहा हूँ जहाँ GetModuleDirectory इसमें ".." भागों के साथ एक पथ देता है, जैसे कि यह कमांड लाइन लोल से स्ट्रिंग को शुद्ध कच्चा ले रहा था। वास्तव में इस मामले में दृश्य स्टूडियो प्रक्रिया शुरू कर रहा है और .. डिबगिंग पथ का हिस्सा है। $ (projectDir) की तरह कुछ .. / some.exe मैंने शालिब से PathCanonicalize का उपयोग किया है लेकिन किसी को इस दायित्व के खिलाफ लिंक करने की आवश्यकता है। यह वांछनीय नहीं हो सकता है।
v.oddou

1
मुझे भी चरक के बजाय स्वयं के लिए TCHAR का उपयोग करने का पुनर्मिलन होगा। लेकिन अच्छा जवाब वैसे भी।
एनोप्‍पी

क्या इसके लिए असफल होना भी संभव है? एक नज़र में इसकी संभावना कम ही लगती है ...HMODULE hModule = GetModuleHandle(NULL);
kayleeFrye_onDeck

1
यदि GetModuleFileName के लिए पहला पैरामीटर NULL है, तो यह वर्तमान प्रक्रिया की निष्पादन योग्य फ़ाइल का पथ पुनर्प्राप्त करता है।
lsalamon

12

विंडोज के लिए:

GetModuleFileName - exe पथ + exe फ़ाइल नाम लौटाता है

फ़ाइल नाम हटाने के लिए
PathRemoveFileSpec


1
PathRemoveFileSpec के लिए दस्तावेज़ नोट This function is deprecated. We recommend the use of the PathCchRemoveFileSpec function in its place:।
जावेद

12

C ++ 17, विंडोज़, यूनिकोड, फाइलसिस्टम नई एपीआई का उपयोग कर:

#include "..\Project.h"
#include <filesystem>
using namespace std;
using namespace filesystem;

int wmain(int argc, wchar_t** argv)
{
    auto dir = weakly_canonical(path(argv[0])).parent_path();
    printf("%S", dir.c_str());
    return 0;
}

इस समाधान पर संदेह पोर्टेबल होना चाहिए, लेकिन पता नहीं है कि अन्य ओएस पर यूनिकोड कैसे लागू किया जाता है।

यदि आप आउटपुट निर्देशिका ऊपरी फ़ोल्डर संदर्भ ('..') को सरल बनाने के लिए उपयोग करते हैं, तो केवल कम से कम_कोनिक की आवश्यकता होती है। यदि आप इसका उपयोग नहीं करते हैं - इसे हटा दें।

यदि आप डायनेमिक लिंक लाइब्रेरी (.dll /.so) से काम कर रहे हैं, तो आपके पास argv नहीं हो सकता है, तो आप निम्नलिखित समाधान पर विचार कर सकते हैं:

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
}

हेडर के अंदर गार्डस फाइलसिस्टम की उपस्थिति के लिए उचित परीक्षण नहीं है। cppreference दिखाता है कि फ़ीचर टेस्ट मैक्रो का मान फ़ाइलसिस्टम हेडर में ही परिभाषित किया गया है, इसलिए यह निष्कर्ष निकालने से पहले परीक्षण करने के लिए काम नहीं करता है। __has_include () यहां एक बेहतर मानक परीक्षण है।
उल्का पिंड

8

क्यूसी इसे OS अमूर्त के साथ QCoreApplication प्रदान करता है :: applicationDirPath ()


इस के साथ हो रही है QCoreApplication::applicationDirPath: Please instantiate the QApplication object first:। किसी भी विचार कैसे हल करने के लिए?
ग्यूसॉफ्ट

@GuySoft: बस इस QCoreApplicationतरह का एक उदाहरण बनाएं QApplication application(argc, argv);(अपने में ऐसा करें main(argc, argv), और सुनिश्चित करें कि आप इसे संशोधित नहीं करते हैं argc/argv, क्योंकि इन की आवश्यकता QCQApplication के जीवनकाल में वैध रहने की है ) ( दस्तावेज की जाँच करें )
ted

5

यह एक विंडोज विशिष्ट तरीका है, लेकिन यह आपके उत्तर का कम से कम आधा हिस्सा है।

GetThisPath.h

/// dest is expected to be MAX_PATH in length.
/// returns dest
///     TCHAR dest[MAX_PATH];
///     GetThisPath(dest, MAX_PATH);
TCHAR* GetThisPath(TCHAR* dest, size_t destSize);

GetThisPath.cpp

#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

TCHAR* GetThisPath(TCHAR* dest, size_t destSize)
{
    if (!dest) return NULL;
    if (MAX_PATH > destSize) return NULL;

    DWORD length = GetModuleFileName( NULL, dest, destSize );
    PathRemoveFileSpec(dest);
    return dest;
}

mainProgram.cpp

TCHAR dest[MAX_PATH];
GetThisPath(dest, MAX_PATH);

मैं प्लेटफ़ॉर्म डिटेक्शन को प्रीप्रोसेसर निर्देशों के रूप में उपयोग करने का सुझाव दूंगा जो GetThisPathप्रत्येक प्लेटफ़ॉर्म के लिए कॉल करने वाले रैपर फ़ंक्शन के कार्यान्वयन को बदल दे ।


3

आर्ग्स का उपयोग करते हुए [0] और '/' (या '\\') की तलाश में:

#include <string>
#include <iostream> // to show the result

int main( int numArgs, char *args[])
{
    // Get the last position of '/'
    std::string aux(args[0]);

    // get '/' or '\\' depending on unix/mac or windows.
#if defined(_WIN32) || defined(WIN32)
    int pos = aux.rfind('\\');
#else
    int pos = aux.rfind('/');
#endif

    // Get the path and the name
    std::string path = aux.substr(0,pos+1);
    std::string name = aux.substr(pos+1);
    // show results
    std::cout << "Path: " << path << std::endl;
    std::cout << "Name: " << name << std::endl;
}

आदर्श: यदि '/' मौजूद नहीं है, तो pos == - 1 इसलिए परिणाम सही है।


क्या होगा अगर '/' पथ में मौजूद नहीं है? उस मामले की कोई जाँच नहीं है और मेरा मानना ​​है कि यह काफी संभावना है - विंडोज बैकस्लैश का उपयोग करेगा, और args[0]वास्तव में बिल्कुल एक रास्ता नहीं हो सकता है।
बेन हाइमरस

यदि '/' मौजूद नहीं है, तो rfind रिटर्न -1, इसलिए "path" = aux.substr (0,0) और "name" = aux.substr (0): परिणाम सही है। विंडोज से संबंधित, आप सही हैं, '/' को '\\' में बदला जाना चाहिए, मैं विंडोज़ को भी अनुमति दूंगा। मैंने '/' के साथ फ़ाइल नाम के लिए भी परीक्षण किया है, लेकिन यह अंतिम कोडित है और समस्याएं पैदा नहीं करता है।
एड्रियन मैयर

1
यह args[0]जरूरी नहीं कि निष्पादन योग्य रास्ता है जो मुझे परेशान करता है। यद्यपि Windows के लिए अपना उत्तर तय करने के लिए धन्यवाद :)
बेन हाइमरस

1
यदि कमांड को पथ दिए बिना चलाया जाता है (अर्थात यह पथ निर्देशिका में दिए गए निर्देशिका में होने से पाया जाता है), तो args [0] केवल पथ के बिना, निष्पादन योग्य का नाम होगा।
केविन

@ केविन: आप (और अन्य) सही हैं, यह एक सरल उपाय है, छोटे उपकरणों के लिए, यह काम ~ 95% मामलों में करता है। गंभीर सॉफ़्टवेयर के लिए, एक कॉन्फ़िगरेशन फ़ाइल और / या एक पर्यावरण चर शायद बेहतर है। इसके अलावा, यह आमतौर पर एक बहुत अच्छा (या भी गलत) डिजाइन की जरूरत नहीं है।
एड्रियन मैयर


1

निम्नलिखित एक त्वरित और गंदे समाधान के रूप में काम करता है, लेकिन ध्यान दें कि यह मूर्ख होने से बहुत दूर है:

#include <iostream>

using namespace std ;

int main( int argc, char** argv)
{
    cout << argv[0] << endl ;
    return 0;
}

17
मैंने अन्य SO प्रश्नों पर देखा है कि यह हमेशा काम नहीं करता है, और उस argv [0] में निष्पादन योग्य पथ हो सकता है, बस निष्पादन योग्य का फ़ाइल नाम, या कोई अन्य बकवास।
बेन हाइमर

7
अगर किसी को 'सपोर्ट फाइल्स' या इस तरह से खोलने की कोशिश की जा रही हो, तो कभी भी argv [0] पर भरोसा नहीं करना चाहिए। आर्गव परिवर्तन के अधीन है, और कोई भी कॉलर जो बुराई है वह इस के मूल्य को बदल सकता है। जब तक आप इसे लॉगिंग के लिए उपयोग नहीं कर रहे हैं, आदि से बचें, फाइलों को खोलने के लिए उपयोग किए जाने वाले रास्तों के निर्माण के लिए नहीं।
Qix - मोनिका ने

यह विंडोज पर काम नहीं करता है। argv [0] के पास पूरा रास्ता नहीं होगा। केवल .exe फ़ाइल। कृपया, एक बैश शेल में कोशिश न करें, इसे ths के मानक कंसोल और cout में आज़माएँ << argv [0] को पुन: उत्पन्न करने के लिए।
फ्रेडी मार्टिनेज गार्सिया

@FreddyMartinezGarcia खैर मैंने इसे Windows में परीक्षण किया होगा, इसलिए YMMV। इसका उपयोग कोड लॉन्च करने के लिए किया जाता था। यदि आप CWD में निष्पादन योग्य हैं तो सुनिश्चित करें कि आप केवल फ़ाइल नाम ही प्राप्त करेंगे।
क्लिफोर्ड

0

मामले में आपको विंडोज के लिए यूनिकोड पथ को संभालने की आवश्यकता है:

#include <Windows.h>
#include <iostream>

int wmain(int argc, wchar_t * argv[])
{
    HMODULE this_process_handle = GetModuleHandle(NULL);
    wchar_t this_process_path[MAX_PATH];

    GetModuleFileNameW(NULL, this_process_path, sizeof(this_process_path));

    std::wcout << "Unicode path of this app: " << this_process_path << std::endl;

    return 0;
}

0

विंडोज के लिए, आपको समस्या है कि निष्पादन योग्य को किस तरह से निकाला जाए GetModuleFileName()। विंडोज एपीआई PathRemoveFileSpec()ने अपने उत्तर में उस उद्देश्य के लिए इस्तेमाल किए गए नैट को विंडोज 8 और उसके पूर्ववर्तियों के बीच बदल दिया। तो कैसे सुरक्षित और सुरक्षित दोनों के साथ संगत रहें? सौभाग्य से, यदि आप एक पुराने संकलक का उपयोग कर रहे हैं, तो C ++ 17 (या बूस्ट) है। मैं यह करता हूँ:

#include <windows.h>
#include <string>
#include <filesystem>
namespace fs = std::experimental::filesystem;

// We could use fs::path as return type, but if you're not aware of
// std::experimental::filesystem, you probably handle filenames
// as strings anyway in the remainder of your code.  I'm on Japanese
// Windows, so wide chars are a must.
std::wstring getDirectoryWithCurrentExecutable()
{
    int size = 256;
    std::vector<wchar_t> charBuffer;
    // Let's be safe, and find the right buffer size programmatically.
    do {
        size *= 2;
        charBuffer.resize(size);
        // Resize until filename fits.  GetModuleFileNameW returns the
        // number of characters written to the buffer, so if the
        // return value is smaller than the size of the buffer, it was
        // large enough.
    } while (GetModuleFileNameW(NULL, charBuffer.data(), size) == size);
    // Typically: c:/program files (x86)/something/foo/bar/exe/files/win64/baz.exe
    // (Note that windows supports forward and backward slashes as path
    // separators, so you have to be careful when searching through a path
    // manually.)

    // Let's extract the interesting part:
    fs::path path(charBuffer.data());  // Contains the full path including .exe
    return path.remove_filename()  // Extract the directory ...
               .w_str();           // ... and convert to a string.
}

0

जैसा कि दूसरों ने उल्लेख किया है, argv[0]काफी अच्छा समाधान है, बशर्ते कि मंच वास्तव में निष्पादन योग्य मार्ग से गुजरता है, जो कि निश्चित रूप से ओएस विंडोज होने की तुलना में कम संभावना नहीं है (जहां WinAPI निष्पादन योग्य मार्ग खोजने में मदद कर सकता है)। यदि आप स्ट्रिप को स्ट्रिप करना चाहते हैं, तो केवल उस डायरेक्टरी में पथ को शामिल करें जहां निष्पादन योग्य रहता है, तो उस पथ का उपयोग करके अन्य एप्लिकेशन फ़ाइलों को खोजने के लिए (जैसे गेम एसेट्स यदि आपका प्रोग्राम एक गेम है) पूरी तरह से ठीक है, क्योंकि फाइल खोलने के सापेक्ष है काम कर रहे निर्देशिका, या, अगर प्रदान की गई, जड़।


0

यह वही है जिसके साथ मैं समाप्त हुआ

शीर्ष लेख फ़ाइल इस प्रकार है:

#pragma once

#include <string>
namespace MyPaths {

  std::string getExecutablePath();
  std::string getExecutableDir();
  std::string mergePaths(std::string pathA, std::string pathB);
  bool checkIfFileExists (const std::string& filePath);

}

कार्यान्वयन


#if defined(_WIN32)
    #include <windows.h>
    #include <Shlwapi.h>
    #include <io.h> 

    #define access _access_s
#endif

#ifdef __APPLE__
    #include <libgen.h>
    #include <limits.h>
    #include <mach-o/dyld.h>
    #include <unistd.h>
#endif

#ifdef __linux__
    #include <limits.h>
    #include <libgen.h>
    #include <unistd.h>

    #if defined(__sun)
        #define PROC_SELF_EXE "/proc/self/path/a.out"
    #else
        #define PROC_SELF_EXE "/proc/self/exe"
    #endif

#endif

namespace MyPaths {

#if defined(_WIN32)

std::string getExecutablePath() {
   char rawPathName[MAX_PATH];
   GetModuleFileNameA(NULL, rawPathName, MAX_PATH);
   return std::string(rawPathName);
}

std::string getExecutableDir() {
    std::string executablePath = getExecutablePath();
    char* exePath = new char[executablePath.length()];
    strcpy(exePath, executablePath.c_str());
    PathRemoveFileSpecA(exePath);
    std::string directory = std::string(exePath);
    delete[] exePath;
    return directory;
}

std::string mergePaths(std::string pathA, std::string pathB) {
  char combined[MAX_PATH];
  PathCombineA(combined, pathA.c_str(), pathB.c_str());
  std::string mergedPath(combined);
  return mergedPath;
}

#endif

#ifdef __linux__

std::string getExecutablePath() {
   char rawPathName[PATH_MAX];
   realpath(PROC_SELF_EXE, rawPathName);
   return  std::string(rawPathName);
}

std::string getExecutableDir() {
    std::string executablePath = getExecutablePath();
    char *executablePathStr = new char[executablePath.length() + 1];
    strcpy(executablePathStr, executablePath.c_str());
    char* executableDir = dirname(executablePathStr);
    delete [] executablePathStr;
    return std::string(executableDir);
}

std::string mergePaths(std::string pathA, std::string pathB) {
  return pathA+"/"+pathB;
}

#endif

#ifdef __APPLE__
    std::string getExecutablePath() {
        char rawPathName[PATH_MAX];
        char realPathName[PATH_MAX];
        uint32_t rawPathSize = (uint32_t)sizeof(rawPathName);

        if(!_NSGetExecutablePath(rawPathName, &rawPathSize)) {
            realpath(rawPathName, realPathName);
        }
        return  std::string(realPathName);
    }

    std::string getExecutableDir() {
        std::string executablePath = getExecutablePath();
        char *executablePathStr = new char[executablePath.length() + 1];
        strcpy(executablePathStr, executablePath.c_str());
        char* executableDir = dirname(executablePathStr);
        delete [] executablePathStr;
        return std::string(executableDir);
    }

    std::string mergePaths(std::string pathA, std::string pathB) {
        return pathA+"/"+pathB;
    }
#endif


bool checkIfFileExists (const std::string& filePath) {
   return access( filePath.c_str(), 0 ) == 0;
}

}

0

SDL2 ( https://www.libsdl.org/ ) लाइब्रेरी में प्लेटफ़ॉर्म की एक विस्तृत स्पेक्ट्रम में दो कार्य कार्यान्वित हैं:

  • SDL_GetBasePath
  • SDL_GetPrefPath

इसलिए यदि आप पहिया को फिर से नहीं लगाना चाहते हैं ... तो दुख की बात है कि इसका मतलब पूरे पुस्तकालय सहित है, हालांकि इसे काफी अनुज्ञेय लाइसेंस मिल गया है और कोई भी कोड को कॉपी कर सकता है। इसके अलावा, यह कई अन्य क्रॉस-प्लेटफॉर्म कार्यक्षमता प्रदान करता है।


0

अधिकांश प्रमुख डेस्कटॉप प्लेटफ़ॉर्म को कवर करते हुए, संभवतः ऐसा करने का यह सबसे स्वाभाविक तरीका है। मैं निश्चित नहीं हूं, लेकिन मेरा मानना ​​है कि यह सभी बीएसडी के साथ काम करना चाहिए, न कि फ्रीबीएसडी, अगर आप उन सभी को कवर करने के लिए प्लेटफॉर्म मैक्रो चेक को बदलते हैं। अगर मैं कभी सोलारिस स्थापित करने के लिए इधर-उधर हो जाता हूं, तो मुझे उस प्लेटफ़ॉर्म को समर्थित सूची में जोड़ना होगा।

विंडोज पर पूर्ण UTF-8 समर्थन की सुविधा है, जो हर कोई उस दूर जाने के लिए पर्याप्त परवाह नहीं करता है।

procinfo / Win32 / procinfo.cpp

#ifdef _WIN32
#include "../procinfo.h"
#include <windows.h>
#include <tlhelp32.h>
#include <cstddef>
#include <vector>
#include <cwchar>

using std::string;
using std::wstring;
using std::vector;
using std::size_t;

static inline string narrow(wstring wstr) {
  int nbytes = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
  vector<char> buf(nbytes);
  return string{ buf.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), buf.data(), nbytes, NULL, NULL) };
}

process_t ppid_from_pid(process_t pid) {        
  process_t ppid;       
  HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);      
  PROCESSENTRY32 pe = { 0 };        
  pe.dwSize = sizeof(PROCESSENTRY32);       
  if (Process32First(hp, &pe)) {        
    do {        
      if (pe.th32ProcessID == pid) {        
        ppid = pe.th32ParentProcessID;      
        break;      
      }     
    } while (Process32Next(hp, &pe));       
  }     
  CloseHandle(hp);      
  return ppid;      
}

string path_from_pid(process_t pid) {
  string path;
  HANDLE hm = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
  MODULEENTRY32W me = { 0 };
  me.dwSize = sizeof(MODULEENTRY32W);
  if (Module32FirstW(hm, &me)) {
    do {
      if (me.th32ProcessID == pid) {
        path = narrow(me.szExePath);
        break;
      }
    } while (Module32NextW(hm, &me));
  }
  CloseHandle(hm);
  return path;
}
#endif

procinfo / MacOSX / procinfo.cpp

#if defined(__APPLE__) && defined(__MACH__)
#include "../procinfo.h"
#include <libproc.h>

using std::string;

string path_from_pid(process_t pid) {
  string path;
  char buffer[PROC_PIDPATHINFO_MAXSIZE];
  if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0) {
    path = string(buffer) + "\0";
  }
  return path;
}
#endif

procinfo / linux / procinfo.cpp

#ifdef __linux__
#include "../procinfo.h"
#include <cstdlib>

using std::string;
using std::to_string;

string path_from_pid(process_t pid) {
  string path;
  string link = string("/proc/") + to_string(pid) + string("/exe");
  char *buffer = realpath(link.c_str(), NULL);
  path = buffer ? : "";
  free(buffer);
  return path;
}
#endif

procinfo / FreeBSD / procinfo.cpp

#ifdef __FreeBSD__
#include "../procinfo.h"
#include <sys/sysctl.h>
#include <cstddef>

using std::string;
using std::size_t;

string path_from_pid(process_t pid) {
  string path;
  size_t length;
  // CTL_KERN::KERN_PROC::KERN_PROC_PATHNAME(pid)
  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid };
  if (sysctl(mib, 4, NULL, &length, NULL, 0) == 0) {
    path.resize(length, '\0');
    char *buffer = path.data();
    if (sysctl(mib, 4, buffer, &length, NULL, 0) == 0) {
      path = string(buffer) + "\0";
    }
  }
  return path;
}
#endif

procinfo / procinfo.cpp

#include "procinfo.h"
#ifdef _WiN32
#include <process.h>
#endif
#include <unistd.h>
#include <cstddef>

using std::string;
using std::size_t;

process_t pid_from_self() {
  #ifdef _WIN32
  return _getpid();
  #else
  return getpid();
  #endif
}

process_t ppid_from_self() {
  #ifdef _WIN32
  return ppid_from_pid(pid_from_self());
  #else
  return getppid();
  #endif
}

string dir_from_pid(process_t pid) {
  string fname = path_from_pid(pid);
  size_t fp = fname.find_last_of("/\\");
  return fname.substr(0, fp + 1);
}

string name_from_pid(process_t pid) {
  string fname = path_from_pid(pid);
  size_t fp = fname.find_last_of("/\\");
  return fname.substr(fp + 1);
}

procinfo / procinfo.h

#ifdef _WiN32
#include <windows.h>
typedef DWORD process_t;
#else
#include <sys/types.h>
typedef pid_t process_t;
#endif
#include <string>

/* windows-only helper function */
process_t ppid_from_pid(process_t pid);

/* get current process process id */
process_t pid_from_self();

/* get parent process process id */
process_t ppid_from_self();

/* std::string possible_result = "C:\\path\\to\\file.exe"; */
std::string path_from_pid(process_t pid);

/* std::string possible_result = "C:\\path\\to\\"; */
std::string dir_from_pid(process_t pid);

/* std::string possible_result = "file.exe"; */
std::string name_from_pid(process_t pid);

यह बहुत अधिक किसी भी प्रक्रिया आईडी के निष्पादन योग्य के लिए पूर्ण पथ प्राप्त करने की अनुमति देता है, विंडोज पर छोड़कर कुछ प्रक्रियाएं सुरक्षा विशेषताओं के साथ होती हैं जो बस इसे अनुमति नहीं देंगी, इसलिए wysiwyg, यह समाधान सही नहीं है।

यह पता करने के लिए कि प्रश्न क्या अधिक सटीक पूछ रहा था, आप ऐसा कर सकते हैं:

procinfo.cpp

#include "procinfo/procinfo.h"
#include <iostream>

using std::string;
using std::cout;
using std::endl;

int main() {
  cout << dir_from_pid(pid_from_self()) << endl;
  return 0;
}

इस आदेश के साथ उपरोक्त फ़ाइल संरचना बनाएँ:

procinfo.sh

cd "${0%/*}"
g++ procinfo.cpp procinfo/procinfo.cpp procinfo/win32/procinfo.cpp procinfo/macosx/procinfo.cpp procinfo/linux/procinfo.cpp procinfo/freebsd/procinfo.cpp -o procinfo.exe

ऊपर सूचीबद्ध फ़ाइलों की एक प्रति डाउनलोड करने के लिए:

git clone git://github.com/time-killer-games/procinfo.git

अधिक क्रॉस-प्लेटफ़ॉर्म प्रक्रिया से संबंधित अच्छाई के लिए:

https://github.com/time-killer-games/enigma-dev

अधिकांश कार्यों की सूची के लिए रीडमी देखें।


0

यदि C ++ 17 का उपयोग किया जा रहा है, तो निष्पादन योग्य पथ प्राप्त करने के लिए निम्न कार्य कर सकते हैं।

#include <filesystem>

std::filesystem::path getExecutablePath()
{
    return std::filesystem::canonical("/proc/self/exe");
}

उपरोक्त उत्तर को G ++ 9.3.0 का उपयोग करके डेबियन 10 पर परीक्षण किया गया है


ध्यान दें कि यह तभी काम करेगा जब / proc / self / exe मौजूद हो और सुलभ हो। अगर यह मामला है तो आपको शायद जांच करनी चाहिए।
ज़रीन

-1

C ++ 17 के अनुसार:

सुनिश्चित करें कि आप std फाइलसिस्टम को शामिल करते हैं।

#include <filesystem>

और अब आप यह कर सकते हैं।

std::filesystem::current_path().string()

बूस्ट फाइलसिस्टम मानक लिब का हिस्सा बन गया।

यदि आप इसे देख पाने की कोशिश नहीं कर सकते हैं:

std::experimental::filesystem

10
यह बाइनरी का मार्ग नहीं है, यह वर्तमान कार्यशील निर्देशिका है।
Zitrax

-2

यह विंडोज में मेरा समाधान था। इसे इस तरह कहा जाता है:

std::wstring sResult = GetPathOfEXE(64);

जहां 64 न्यूनतम आकार है, आपको लगता है कि रास्ता होगा। GetPathOfEXE खुद को पुनरावर्ती कहता है, हर बार बफर के आकार को दोगुना करता है जब तक कि यह पूरे रास्ते को रौंदने के लिए एक बड़ा पर्याप्त बफर नहीं मिलता है।

std::wstring GetPathOfEXE(DWORD dwSize)
{
    WCHAR* pwcharFileNamePath;
    DWORD dwLastError;
    HRESULT hrError;
    std::wstring wsResult;
    DWORD dwCount;

    pwcharFileNamePath = new WCHAR[dwSize];

    dwCount = GetModuleFileNameW(
        NULL,
        pwcharFileNamePath,
        dwSize
    );

    dwLastError = GetLastError();

    if (ERROR_SUCCESS == dwLastError)
    {
        hrError = PathCchRemoveFileSpec(
            pwcharFileNamePath,
            dwCount
        );

        if (S_OK == hrError)
        {
            wsResult = pwcharFileNamePath;

            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            return wsResult;
        }
        else if(S_FALSE == hrError)
        {
            wsResult = pwcharFileNamePath;

            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            //there was nothing to truncate off the end of the path
            //returning something better than nothing in this case for the user
            return wsResult;
        }
        else
        {
            if (pwcharFileNamePath)
            {
                delete pwcharFileNamePath;
            }

            std::ostringstream oss;
            oss << "could not get file name and path of executing process. error truncating file name off path. last error : " << hrError;
            throw std::runtime_error(oss.str().c_str());
        }
    }
    else if (ERROR_INSUFFICIENT_BUFFER == dwLastError)
    {
        if (pwcharFileNamePath)
        {
            delete pwcharFileNamePath;
        }

        return GetPathOfEXE(
            dwSize * 2
        );
    }
    else
    {
        if (pwcharFileNamePath)
        {
            delete pwcharFileNamePath;
        }

        std::ostringstream oss;
        oss << "could not get file name and path of executing process. last error : " << dwLastError;
        throw std::runtime_error(oss.str().c_str());
    }
}

new(और) गलत का उपयोग करने का कारण क्या है delete? यदि आपने उपयोग किया है std::vector, तो आपके कोड ने अपरिभाषित व्यवहार प्रदर्शित नहीं किया होगा।
IInspectable

इसके अलावा, GetModuleFileNameWसफलता के मामले में अंतिम त्रुटि कोड निर्धारित नहीं करता है। वह कोड इतने तरीकों से टूटा है। यदि आप इस पर ठोकर खाते हैं तो उपयोग न करें।
IInspectable

-3
char exePath[512];
CString strexePath;
GetModuleFileName(NULL,exePath,512);
strexePath.Format("%s",exePath);
strexePath = strexePath.Mid(0,strexePath.ReverseFind('\\'));

2
यह केवल विंडोज है और MFC का उपयोग करता है, इसलिए क्रॉस-प्लेटफॉर्म से बहुत दूर है, क्षमा करें!
बेन हाइमर

1
यह ऐसा करने का विंडोज तरीका भी नहीं है। PathRemoveFileSpec()इसके बजाय संबंधित कार्यों पर एक नज़र डालें ।
रेमी लेबेउ

-4

यूनिक्स में (लिनक्स सहित) कोशिश 'जो', विंडोज में 'जहां' की कोशिश करें।

#include <stdio.h>

#define _UNIX

int main(int argc, char** argv)
{
        char cmd[128];
        char buf[128];
        FILE* fp = NULL;
#if defined(_UNIX)
        sprintf(cmd, "which %s > my.path", argv[0]);
#else
        sprintf(cmd, "where %s > my.path", argv[0]);
#endif
        system(cmd);
        fp = fopen("my.path", "r");
        fgets(buf, sizeof(buf), fp);
        fclose(fp);

        printf("full path: %s\n", buf);
        unlink("my.path");

        return 0;
}

-4

यह विधि विंडोज और लिनक्स दोनों के लिए काम करती है:

#include <stdio.h>
#include <string>
#ifdef _WIN32
#include <direct.h>
#define GetCurrentDir _getcwd
#elif __linux__
#include <unistd.h>
#define GetCurrentDir getcwd
#endif

std::string GetCurrentWorkingDir() 
{
    char buff[FILENAME_MAX];
    GetCurrentDir(buff, FILENAME_MAX);
    std::string current_working_dir(buff);
    return current_working_dir;
}

2
यह वर्तमान कार्यशील निर्देशिका को लौटाता है, निष्पादन योग्य को पथ नहीं जो एक ही बात नहीं हो सकती है।
डेव डर्बिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.