2010-01-12 6 views
73

सी या सी ++ एप्लिकेशन में main() पर तर्क पारित करते समय, argv[0] हमेशा निष्पादन योग्य का नाम होगा? या यह सिर्फ एक आम सम्मेलन है और 100% सही होने की गारंटी नहीं है?"argv [0] = नाम-निष्पादन योग्य" एक स्वीकृत मानक या सिर्फ एक आम सम्मेलन है?

+16

यूनिक्स पर, विचार करें: 'execl ("/ home/हैकर/.hidden/malicious", "/ bin/ls", "-s", (char *) 0); '। निष्पादन योग्य भालू का नाम 'argv [0]' में मान से कोई संबंध नहीं है। –

उत्तर

89

अनुमान (यहां तक ​​कि शिक्षित अनुमान) मजेदार है लेकिन आपको वास्तव में सुनिश्चित करने के लिए मानक दस्तावेजों पर जाना होगा। उदाहरण के लिए, आईएसओ C11 राज्यों (मेरे जोर):

तो argc का मूल्य शून्य से अधिक है, स्ट्रिंग argv[0]का प्रतिनिधित्व करता है के द्वारा प्रोग्राम नाम की ओर इशारा किया, argv[0][0] शून्य वर्ण होगा यदि प्रोग्राम का नाम मेजबान वातावरण से उपलब्ध नहीं है।

तो नहीं, यह केवल प्रोग्राम नाम है यदि वह नाम उपलब्ध है। और यह प्रोग्राम का नाम "" का प्रतिनिधित्व करता है, आवश्यक नहीं प्रोग्राम नाम है। उससे पहले खंड में कहा गया है:

तो argc का मूल्य शून्य से अधिक है, सरणी सदस्यों argv[argc-1] समावेशी तार है, जो मेजबान वातावरण स्टार्टअप प्रोग्राम के लिए पहले से कार्यान्वयन से परिभाषित मूल्यों दिया जाता है की ओर इशारा शामिल होगा के माध्यम से argv[0]

यह C99, पिछले मानक से अपरिवर्तित है, और इसका मतलब है कि यहां तक ​​कि मूल्यों मानक से निर्धारित नहीं कर रहे हैं - यह पूरी तरह से कार्यान्वयन पर निर्भर है।

इसका मतलब यह है कि इस कार्यक्रम का नाम खाली हो सकता है अगर मेजबान वातावरण यह प्रदान नहीं करता है, और कुछ और अगर मेजबान वातावरण करता यह प्रदान करते हैं, बशर्ते कि "कुछ और" किसी भी तरह प्रोग्राम नाम का प्रतिनिधित्व करता है। मेरे अधिक दुखद क्षणों में, मैं इसे स्वाहिली में अनुवाद करने पर विचार करता हूं, इसे प्रतिस्थापन सिफर के माध्यम से चलाता हूं और फिर इसे रिवर्स बाइट ऑर्डर में संग्रहीत करता हूं :-)।

हालांकि, कार्यान्वयन-परिभाषित आईएसओ मानकों में एक विशिष्ट अर्थ है - कार्यान्वयन को यह दस्तावेज करना चाहिए कि यह कैसे काम करता है। तो यूनिक्स भी, जो में exec कॉल के परिवार के साथ कुछ भी डाल सकता है, उसे दस्तावेज़ (और करता है) करना है।

+0

क्या आप इस मानक दस्तावेज़ के लिए एक लिंक जोड़ सकते हैं, तो हम सभी को पढ़ा जा सकता है? धन्यवाद। – liwp

+3

यह मानक हो सकता है, लेकिन यूनिक्स बस इसे लागू नहीं करता है, और आप इस पर भरोसा नहीं कर सकते हैं। – dmckee

+4

प्रश्न में यूनिक्स * का उल्लेख नहीं किया गया *। यह सी प्रश्न सादा और सरल था, इसलिए आईएसओ सी संदर्भ का दस्तावेज है। कार्यक्रम का नाम मानक में परिभाषित कार्यान्वयन है, इसलिए एक कार्यान्वयन जो कुछ भी चाहता है, वह करने के लिए स्वतंत्र है, जिसमें वास्तविक नाम नहीं है, जिसमें मैंने सोचा था कि मैंने अंतिम वाक्य में यह स्पष्ट कर दिया होगा। – paxdiablo

4

This page कहता है:

तत्व argv [0] सामान्य रूप से कार्यक्रम का नाम है, लेकिन इस पर भरोसा नहीं किया जाना चाहिए - वैसे भी यह एक प्रोग्राम अपने नाम पता करने के लिए नहीं के लिए असामान्य है!

हालांकि, अन्य पृष्ठ इस तथ्य का समर्थन करते हैं कि यह हमेशा निष्पादन योग्य का नाम है। This one कहता है:

आप देखेंगे कि argv [0] प्रोग्राम का पथ और नाम है। यह कार्यक्रम को अपने बारे में जानकारी खोजने की अनुमति देता है। यह प्रोग्राम तर्कों की सरणी में एक और भी जोड़ता है, इसलिए कमांड लाइन तर्क प्राप्त करते समय एक सामान्य त्रुटि argv [0] को पकड़ने के लिए है जब आप argv [1] चाहते हैं।

+10

कुछ कार्यक्रम इस तथ्य का लाभ उठाते हैं कि उन्हें उस नाम को नहीं पता जिसे उनका उपयोग करने के लिए उपयोग किया गया था। मेरा मानना ​​है कि BusyBox (http://www.busybox.net/about.html) इस तरह से काम करता है। केवल एक निष्पादन योग्य है जो कई अलग-अलग कमांड लाइन उपयोगिता लागू करता है। यह निर्धारित करने के लिए प्रतीकात्मक लिंक और argv [0] का एक गुच्छा का उपयोग करता है यह निर्धारित करने के लिए कि क्या कमांड लाइन उपकरण चलाना चाहिए – Trent

+0

हाँ, मुझे याद है कि "गनज़िप" "gzip" के लिए एक प्रतीकात्मक लिंक था, और एक पल के लिए सोच रहा था कि यह कैसे काम करता है। –

+2

कई कार्यक्रम जानकारी के लिए argv [0] को देखते हैं; उदाहरण के लिए, यदि नाम का अंतिम घटक डैश ('/ bin/-sh', उदाहरण के लिए) से शुरू होता है, तो खोल लॉग इन खोल के लिए प्रोफाइल और अन्य सामान चलाएगा। –

8

सी ++ मानक के अनुसार, खंड 3.6.1:

argv [0] एक NTMBS की प्रारंभिक चरित्र सूचक होगा कि कार्यक्रम आह्वान करने के लिए इस्तेमाल नाम का प्रतिनिधित्व करता है या "

तो नहीं, कम से कम मानक द्वारा इसकी गारंटी नहीं है।

+4

मुझे लगता है कि यह निरस्त बहु-बाइट स्ट्रिंग समाप्त हो गया है? – paxdiablo

+1

हां वास्तव में यह है। –

40

*nix तहत exec*() कॉल के साथ प्रकार सिस्टम, argv[0] हो जाएगा जो कुछ भी फोन करने वाले exec*() कॉल में argv0 स्थान में डालता है।

खोल इस सम्मेलन का उपयोग करता है कि यह कार्यक्रम का नाम है, और अधिकांश अन्य कार्यक्रम एक ही सम्मेलन का पालन करते हैं, इसलिए argv[0] आमतौर पर प्रोग्राम का नाम।

लेकिन एक दुष्ट यूनिक्स प्रोग्राम exec() पर कॉल कर सकता है और argv[0] कुछ भी पसंद करता है, तो कोई फर्क नहीं पड़ता कि सी मानक क्या कहता है, आप इस 100% समय पर भरोसा नहीं कर सकते हैं।

+4

यह पक्सडीब्लो के ऊपर से बेहतर जवाब है। मानक सिर्फ इसे "प्रोग्राम नाम" कहते हैं, लेकिन यह मेरे ज्ञान के लिए कहीं भी लागू नहीं है। यूनिक्स कर्नेल समान रूप से निष्पादित करने के लिए पारित स्ट्रिंग को पार करते हैं() बच्चे की प्रक्रिया में अपरिवर्तित। –

+4

सी मानक जो कह सकता है उसमें सीमित है क्योंकि इसे 'execve()' आदि के बारे में पता नहीं है। POSIX मानक (http://www.opengroup.org/onlinepubs/9699919799/functions/execve.html) में है कहने के लिए और अधिक - यह स्पष्ट करना कि Argv [0] में क्या है, 'execve()' (या संबंधित) सिस्टम कॉल निष्पादित करने की प्रक्रिया के दौरान है। –

+1

@ एंडी, आप अपनी राय रखने के लिए स्वतंत्र हैं :-) लेकिन आप प्रवर्तन के बारे में गलत हैं। यदि कोई कार्यान्वयन मानक का पालन नहीं करता है तो यह गैर-अनुरूप है। और वास्तव में, चूंकि यह कार्यान्वयन-परिभाषित है कि "प्रोग्राम नाम" क्या है, यूनिक्स * जैसे ओएस * अनुरूप है जब तक यह निर्दिष्ट करता है कि नाम क्या है। इसमें कॉल के निष्पादन परिवार में जो कुछ भी आप चाहते हैं उसके साथ argv [0] लोड करके प्रोग्राम प्रोग्राम को नकली रूप से नकली करने में सक्षम होना शामिल है। – paxdiablo

4

आईएसओ आईईसी 9899 राज्यों:

5.1.2.2.1 कार्यक्रम स्टार्टअप

तो argc का मूल्य शून्य से अधिक है, स्ट्रिंग द्वारा argv[0] का प्रतिनिधित्व करता है की ओर इशारा किया कार्यक्रम का नाम; argv[0][0] होस्ट नाम से प्रोग्राम नाम उपलब्ध नहीं है, तो शून्य वर्ण होगा। यदि argc का मूल्य एक से अधिक है, तार के माध्यम से argv[argc-1]argv[1] द्वारा की ओर इशारा प्रतिनिधित्व कार्यक्रम पैरामीटर

मैं भी उपयोग किया है:

#if defined(_WIN32) 
    static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) 
    { 
    return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity); 
    } 
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */ 
    #include <unistd.h> 
    static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) 
    { 
    size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1); 
    pathName[pathNameSize] = '\0'; 
    return pathNameSize; 
    } 
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */ 
    #include <mach-o/dyld.h> 
    static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity) 
    { 
    uint32_t pathNameSize = 0; 

    _NSGetExecutablePath(NULL, &pathNameSize); 

    if (pathNameSize > pathNameCapacity) 
     pathNameSize = pathNameCapacity; 

    if (!_NSGetExecutablePath(pathName, &pathNameSize)) 
    { 
     char real[PATH_MAX]; 

     if (realpath(pathName, real) != NULL) 
     { 
     pathNameSize = strlen(real); 
     strncpy(pathName, real, pathNameSize); 
     } 

     return pathNameSize; 
    } 

    return 0; 
    } 
#else /* else of: #elif defined(__APPLE__) */ 
    #error provide your own implementation 
#endif /* end of: #if defined(_WIN32) */ 

और फिर तुम सिर्फ स्ट्रिंग पथ से निष्पादन योग्य नाम निकालने के लिए पार्स करने के लिए की है।

+2

'/ proc/self/path/a.out' symlink Solaris 10 और ऊपर पर प्रयोग योग्य हो सकता है। – ephemient

+0

कोड के लिए उपरोक्त (यह आदर्श या सही नहीं कह रहा है, उदाहरण के लिए विंडोज 'GetModuleFileNameW' पर किसी भी पथ को पुनः प्राप्त करने में सक्षम होने के लिए उपयोग किया जाना चाहिए, लेकिन कोड की उपस्थिति अच्छी मार्गदर्शन का गठन करती है)। –

+0

बीटीडब्ल्यू, हाल ही में मैंने https://github.com/gpakosz/whereami –

2

मुझे यकीन नहीं है कि यह लगभग सार्वभौमिक सम्मेलन या मानक है, लेकिन किसी भी तरह से आपको इसका पालन करना चाहिए। मैंने कभी यूनिक्स और यूनिक्स जैसी प्रणालियों के बाहर इसका शोषण नहीं देखा है। यूनिक्स वातावरण में - और शायद विशेष रूप से पुराने दिनों में - कार्यक्रमों के नाम के आधार पर कार्यक्रमों के काफी अलग व्यवहार हो सकते हैं जिनके तहत उन्हें बुलाया जाता है।

संपादित: मैं एक ही समय में अन्य पदों से देखता हूं कि किसी ने इसे किसी विशेष मानक से आने के रूप में पहचाना है, लेकिन मुझे यकीन है कि सम्मेलन लंबे समय से मानक की भविष्यवाणी करता है।

+1

जारी किया है, मुझे यकीन है कि अगर लोग मेरी प्रतिक्रिया को "चिह्नित" करने जा रहे हैं तो वे कुछ संकेत देंगे कि उन्हें इसके बारे में क्या पसंद नहीं है। –

2

Runnable POSIX execve उदाहरण है जहाँ argv[0] != निष्पादन योग्य नाम

दूसरों exec उल्लेख किया है, लेकिन यहाँ एक runnable उदाहरण है।

a.c

#define _XOPEN_SOURCE 700 
#include <unistd.h> 

int main(void) { 
    char *argv[] = {"yada yada", NULL}; 
    char *envp[] = {NULL}; 
    execve("b.out", argv, envp); 
} 

b.c

#include <stdio.h> 

int main(int argc, char **argv) { 
    puts(argv[0]); 
} 

तब:

gcc a.c -o a.out 
gcc b.c -o b.out 
./a.out 

देता है:

012,
yada yada 

हाँ, argv[0] भी हो सकता है:

उबंटू 16.10 पर परीक्षण किया गया।

संबंधित मुद्दे