printf जैसे वैरिएडिक फ़ंक्शंस उनके द्वारा प्राप्त तर्कों की संख्या का पता कैसे लगा सकते हैं?
तर्कों की मात्रा स्पष्ट रूप से एक (छिपे हुए) पैरामीटर के रूप में पारित नहीं होती है (देखें एएसएम उदाहरण में प्रिंटफ को यहां कॉल करें)।
चाल क्या है?
4 जवाब
चाल यह है कि आप उन्हें किसी और तरह से बताते हैं। printf
के लिए आपको एक प्रारूप स्ट्रिंग की आपूर्ति करनी होगी जिसमें प्रकार की जानकारी भी हो (जो कि गलत हो सकती है)। इस जानकारी की आपूर्ति करने का तरीका मुख्य रूप से उपयोगकर्ता-अनुबंध और अक्सर त्रुटि-प्रवण होता है।
सम्मेलनों को बुलाने के लिए: आम तौर पर तर्कों को बाएं से दाएं स्टैक पर धक्का दिया जाता है और फिर बैकजंप पता अंत में होता है। कॉलिंग रूटीन स्टैक को साफ करता है। इसलिए मापदंडों की संख्या जानने के लिए कॉलेड रूटीन की कोई तकनीकी आवश्यकता नहीं है।
संपादित करें: सी ++ 0x में विविध कार्यों को कॉल करने के लिए एक सुरक्षित तरीका (यहां तक कि टाइपएफ़!)
स्पष्ट रूप से, प्रारूप स्ट्रिंग से। ध्यान दें कि पारित किए गए तर्कों की कुल "चर" संख्या को पुनः प्राप्त करने के लिए stdarg.h में कोई मैक्रोज़ नहीं है। यह भी एक कारण है कि सी कॉलिंग कन्वेंशन के लिए कॉलर को स्टैक को साफ करने की आवश्यकता होती है, भले ही यह कोड आकार को बढ़ाता है।
यही कारण है कि सी कॉलिंग कन्वेंशन पर रिवर्स ऑर्डर पर तर्कों को धक्का दिया जाता है, जैसे:
यदि आप कॉल करते हैं:
printf("%s %s", foo, bar);
ढेर की तरह समाप्त होता है:
...
+-------------------+
| bar |
+-------------------+
| foo |
+-------------------+
| "%s %s" |
+-------------------+
| return address |
+-------------------+
| old frame pointer | <- frame pointer
+-------------------+
...
तर्कों को परोक्ष रूप से फ्रेम पॉइंटर से ऑफसेट का उपयोग करके एक्सेस किया जाता है (फ्रेम पॉइंटर को स्मार्ट कंपाइलर्स द्वारा छोड़ा जा सकता है जो स्टैक पॉइंटर से चीजों की गणना करना जानते हैं)। इस योजना में पहला तर्क हमेशा एक प्रसिद्ध पते पर होता है, फ़ंक्शन उतने तर्कों तक पहुँचता है जितना कि इसके पहले तर्क इसे बताते हैं।
निम्नलिखित का प्रयास करें:
printf("%x %x %x %x %x %x\n");
यह ढेर के हिस्से को डंप कर देगा।
AMD64 सिस्टम V ABI(लिनक्स, मैक ओएस एक्स) पास नहीं होता है किसी भी मानक IA-32 कॉलिंग सम्मेलनों के विपरीत,
al
(RAX की निम्न बाइट) में संख्या वेक्टर (SSE / AVX) भिन्न होता है। यह भी देखें: प्रिंटफ को कॉल करने से पहले %eax को शून्य क्यों किया जाता है?लेकिन केवल 8 तक (उपयोग करने के लिए रजिस्टरों की अधिकतम संख्या)। और IIRC, ABI
al
को XMM/YMM/ZMM args की वास्तविक संख्या से अधिक होने की अनुमति देता है लेकिन यह कम नहीं होना चाहिए। तो यह सामान्य रूप से आपको हमेशा FP args की संख्या नहीं बताता है; आप यह नहीं बता सकते कि 8 से अधिक कितने हैं, औरal
को अधिक गणना करने की अनुमति है।यह केवल प्रदर्शन कारणों के लिए प्रयोग करने योग्य है, अनावश्यक वेक्टर रजिस्टरों को "3.5.7 परिवर्तनीय तर्क सूची" में उल्लिखित "रजिस्टर सेव एरिया" में सहेजना छोड़ना है। उदाहरण के लिए GCC कोड बनाता है जो
al!=0
का परीक्षण करता है और फिर XMM0..7 को स्टैक या कुछ भी नहीं डंप करता है। (या यदि फ़ंक्शनVA_ARG
__m256
के साथ कहीं भी उपयोग करता है, तो YMM0..7।)सी स्तर पर, प्रारूप स्ट्रिंग को पार्स करने के अलावा अन्य तकनीकें भी हैं जैसा कि दूसरों ने बताया है। आप यह भी कर सकते हैं:
अंतिम तर्क जैसे निष्पादित करता है।
आप
sentinel
फ़ंक्शन विशेषता का उपयोग करना चाहेंगे ताकि GCC को संकलन समय पर इसे लागू करने में मदद मिल सके: सी चेतावनी फंक्शन कॉल में सेंटीनेल गुम होनाइसे varargs की संख्या के साथ एक अतिरिक्त पूर्णांक तर्क के रूप में पास करें
format
फ़ंक्शन विशेषता का उपयोग करके GCC कोprintf
याstrftime
जैसे ज्ञात प्रकारों के प्रारूप स्ट्रिंग को लागू करने में सहायता करें
संबंधित: gcc में वेरिएबल तर्कों को कैसे लागू किया जाता है?
संबंधित सवाल
जुड़े हुए प्रश्न
नए सवाल
assembly
विधानसभा भाषा के प्रश्न। कृपया प्रोसेसर और / या आपके द्वारा उपयोग किए जा रहे निर्देश सेट को टैग करें, साथ ही कोडांतरक, एक वैध सेट इस तरह होना चाहिए: (असेंबली, x86, gnu) ध्यान दें कि आपको इसके बजाय ".net-विधानसभा" टैग का उपयोग करना चाहिए। .NET असेंबली लैंग्वेज और जावा बाइटकोड के लिए, इसके बजाय टैग जावा-बायटेकोड-एएसएम का उपयोग करें।