कोई फ़ंक्शन जिसके पास कोई पैरामीटर नहीं है (वास्तविक फ़ंक्शन परिभाषा की तुलना में) संकलन करता है?


388

मैं अभी किसी के सी कोड में आया हूं कि मैं उलझन में हूं कि यह क्यों संकलन कर रहा है। दो बिंदु हैं जो मुझे समझ नहीं आ रहे हैं।

सबसे पहले, फ़ंक्शन प्रोटोटाइप में वास्तविक फ़ंक्शन परिभाषा की तुलना में कोई पैरामीटर नहीं है। दूसरा, फ़ंक्शन परिभाषा में पैरामीटर का प्रकार नहीं है।

#include <stdio.h>

int func();

int func(param)
{
    return param;
}

int main()
{
    int bla = func(10);    
    printf("%d", bla);
}

यह काम क्यों करता है? मैंने इसे एक-दो कंपाइलर में टेस्ट किया है, और यह ठीक काम करता है।


77
यह K & R C. है। हमने 1980 के दशक में इस तरह का कोड लिखा था, इससे पहले फुल प्रोटोटाइप थे।
हुग्डब्रोर्न

6
gcc -Wstrict-prototypesदोनों के साथ चेतावनी देता है int func()और int main(): xc: 3: चेतावनी: फ़ंक्शन घोषणा एक प्रोटोटाइप नहीं है। आप घोषणा करना चाहिए main()के रूप में main(void)अच्छी तरह से।
जेन्स

3
@ जेन्स आपने प्रश्न क्यों संपादित किया? आपको यह बात याद आ गई ...
dlras2

1
मैंने अभी निहित अंतर स्पष्ट किया है। उस बिंदु को कैसे याद करता है? मेरा मानना ​​है कि बिंदु क्यों int func();संगत है int func(arglist) { ... }
जेन्स

3
@MatsPetersson यह गलत है। C99 5.1.2.2.1 स्पष्ट रूप से आपके दावे का खंडन करता है और बताता है कि कोई तर्क संस्करण नहीं है int main(void)
जेन्स

जवाबों:


271

अन्य सभी उत्तर सही हैं, लेकिन सिर्फ पूरा करने के लिए

एक समारोह निम्नलिखित तरीके से घोषित किया जाता है:

  return-type function-name(parameter-list,...) { body... }

रिटर्न-टाइप वैरिएबल टाइप है जो फंक्शन रिटर्न करता है। यह एक सरणी प्रकार या फ़ंक्शन प्रकार नहीं हो सकता है। यदि नहीं दिया जाता है, तो int मान लिया जाता है

function-name फ़ंक्शन का नाम है।

पैरामीटर-सूची उन मापदंडों की सूची है जो फ़ंक्शन कॉमा से अलग हो जाते हैं। यदि कोई पैरामीटर नहीं दिया गया है, तो फ़ंक्शन कोई भी नहीं लेता है और इसे कोष्ठक के खाली सेट या कीवर्ड शून्य के साथ परिभाषित किया जाना चाहिए। यदि पैरामाटर सूची में कोई चर प्रकार सामने नहीं है, तो int मान लिया जाता है । Arrays और फ़ंक्शन फ़ंक्शंस में पारित नहीं होते हैं, लेकिन स्वचालित रूप से पॉइंटर्स में परिवर्तित हो जाते हैं। यदि सूची को एक दीर्घवृत्त (, ...) के साथ समाप्त किया जाता है, तो कोई निर्धारित संख्या पैरामीटर नहीं है। नोट: शीर्ष लेख stdarg.h का उपयोग एक दीर्घवृत्त का उपयोग करते समय तर्कों का उपयोग करने के लिए किया जा सकता है।

और फिर से पूर्णता के लिए। C11 विनिर्देश 6 से: 11: 6 (पृष्ठ: 179)

खाली कोष्ठकों के साथ फ़ंक्शन घोषणाओं का उपयोग (प्रोटोटाइप-प्रारूप पैरामीटर प्रकार घोषणाकर्ता नहीं) एक अप्रचलित विशेषता है


2
"यदि कोई चर प्रकार पैरामीटर सूची में एक चर के सामने है, तो int मान लिया गया है।" मुझे यह आपके द्वारा प्रदान की गई लिंक में दिखाई दे रहा है, लेकिन मैं इसे किसी भी मानक c89, c99 में नहीं ढूँढ सकता ... क्या आप कोई अन्य स्रोत प्रदान कर सकते हैं?
गोडैगो

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

160

सी में func()इसका मतलब है कि आप किसी भी तर्क को पारित कर सकते हैं। यदि आप कोई तर्क नहीं चाहते हैं, तो आपको घोषित करना होगा func(void)। वह प्रकार जो आप अपने फ़ंक्शन से गुजर रहे हैं, यदि निर्दिष्ट डिफ़ॉल्ट के लिए नहीं int


3
वास्तव में इंट करने के लिए कोई एकल प्रकार डिफ़ॉल्ट नहीं है। वास्तव में, सभी डिफ़ॉल्ट रूप से int (यहां तक ​​कि रिटर्न प्रकार) तक पहुंचते हैं। यह कॉल करने के लिए पूरी तरह से ठीक है func(42,0x42);(जहां सभी कॉल को दो args फॉर्म का उपयोग करना चाहिए)।
जेन

1
सी में यह अनिर्दिष्ट प्रकार के लिए डिफ़ॉल्ट के लिए काफी आम है पूर्णांक उदाहरण के लिए जैसे कि जब आप एक चर घोषित: अहस्ताक्षरित x; चर x किस प्रकार का है? यह इसका
अप्रयुक्त

4
मैं कहूंगा कि पुराने दिनों में निहित int सामान्य था । यह निश्चित रूप से अब नहीं है और C99 में इसे C
Jens

2
यह ध्यान देने योग्य हो सकता है कि यह उत्तर रिक्त पैरामीटर सूचियों के साथ फ़ंक्शन को लागू करने के लिए लागू होता है, लेकिन रिक्त पैरामीटर सूची के साथ परिभाषाओं को कार्य नहीं करता है।
ऑटिस्टिक

@memonicflowflow जो "अनिर्दिष्ट प्रकार से डिफ़ॉल्ट के लिए डिफ़ॉल्ट" नहीं है; unsignedउसी प्रकार का दूसरा नाम है unsigned int
हॉब्स

58

int func();उन दिनों से एक अश्लील कार्य घोषणा है जब कोई सी मानक नहीं था, यानी के एंड आर सी के दिन (1989 से पहले, वर्ष "एएनएसआई सी" मानक प्रकाशित किया गया था)।

याद रखें कि K & R C में कोई प्रोटोटाइप नहीं थे और कीवर्ड voidका अभी तक आविष्कार नहीं हुआ था। संकलक को किसी फ़ंक्शन के रिटर्न प्रकार के बारे में बताने के लिए आप सभी कर सकते थे । K & R C में खाली पैरामीटर सूची का अर्थ है "एक अनिर्दिष्ट लेकिन निश्चित" तर्कों की संख्या। फिक्स्ड का मतलब है कि आपको हर बार समान संख्या में आर्ग के साथ फ़ंक्शन को कॉल करना चाहिए (जैसे कि एक वैरिएड फ़ंक्शन के विपरीत printf, जहां संख्या और प्रकार प्रत्येक कॉल के लिए भिन्न हो सकते हैं)।

कई संकलक इस निर्माण का निदान करेंगे; विशेष रूप से gcc -Wstrict-prototypesआपको बताएंगे "फ़ंक्शन घोषणा एक प्रोटोटाइप नहीं है", जो ऑन स्पॉट है, क्योंकि यह एक प्रोटोटाइप की तरह दिखता है (खासकर यदि आप सी ++ द्वारा जहर दिए गए हैं!), लेकिन नहीं। यह एक पुरानी शैली K & R C वापसी प्रकार की घोषणा है।

अंगूठे का नियम: कभी भी खाली पैरामीटर सूची घोषणा को खाली न छोड़ें, int func(void)विशिष्ट होने के लिए उपयोग करें। यह K & R रिटर्न प्रकार की घोषणा को उचित C89 प्रोटोटाइप में बदल देता है। कंपाइलर खुश हैं, डेवलपर्स खुश हैं, स्थिर चेकर्स खुश हैं। ^ W ^ CF Wfond द्वारा उन लोगों को गुमराह किया जा सकता है, हालाँकि, जब वे अपने विदेशी भाषा कौशल का अभ्यास करने की कोशिश करते हैं, तो उन्हें अतिरिक्त वर्ण टाइप करने की आवश्यकता होती है :-)


1
कृपया इसे C ++ से संबंधित न करें। यह सामान्य ज्ञान है कि खाली तर्क सूची का मतलब कोई पैरामीटर नहीं है , और दुनिया के लोग लगभग 40 साल पहले के एंड आर के लोगों द्वारा की गई गलतियों से निपटने के लिए इच्छुक नहीं हैं। लेकिन समिति के पंडित कॉन्टर्नेटिक विकल्पों को साथ-साथ C99, C11 में खींचते रहते हैं।
पफल्कॉन

1
@ पफाल्कन कॉमन सेंस काफी सब्जेक्टिव है। एक व्यक्ति के लिए सामान्य ज्ञान क्या दूसरों के लिए सरल पागलपन है। पेशेवर सी प्रोग्रामर जानते हैं कि खाली पैरामीटर सूचियां एक अनिर्दिष्ट लेकिन निश्चित संख्या में तर्कों का संकेत देती हैं। बदल रहा है कि संभावना कई कार्यान्वयन टूट जाएगा। मूक बदलावों से बचने के लिए दोषपूर्ण समितियों को गलत पेड़, आईएमएचओ भौंक रहा है।
जेन्स

53
  • खाली पैरामीटर सूची का अर्थ है "कोई भी तर्क", इसलिए परिभाषा गलत नहीं है।
  • लापता प्रकार माना जाता है int

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


30

यह K & R स्टाइल फंक्शन डिक्लेरेशन और डेफिनिशन है। C99 स्टैंडर्ड (ISO / IEC 9899: TC3) से

खंड 6.7.5.3 फ़ंक्शन घोषणाकर्ता (प्रोटोटाइप सहित)

एक पहचानकर्ता सूची केवल फ़ंक्शन के मापदंडों के पहचानकर्ताओं की घोषणा करती है। फ़ंक्शन घोषणा में एक खाली सूची जो उस फ़ंक्शन की परिभाषा का हिस्सा है, निर्दिष्ट करती है कि फ़ंक्शन का कोई पैरामीटर नहीं है। एक फ़ंक्शन घोषणा में खाली सूची जो उस फ़ंक्शन की परिभाषा का हिस्सा नहीं है, यह निर्दिष्ट करती है कि मापदंडों की संख्या या प्रकारों के बारे में कोई जानकारी नहीं दी गई है। (यदि दोनों प्रकार के प्रकार "पुरानी शैली" हैं, तो पैरामीटर प्रकार की तुलना नहीं की जाती है।)

खंड 6.11.6 फ़ंक्शन घोषणाकर्ता

खाली कोष्ठक (प्रोटोटाइप-प्रारूप पैरामीटर प्रकार घोषणाकर्ता नहीं) के साथ फ़ंक्शन घोषणाओं का उपयोग एक अश्लील विशेषता है।

खंड 6.11.7 फ़ंक्शन परिभाषाएँ

अलग पैरामीटर पहचानकर्ता और घोषणा सूचियों के साथ फ़ंक्शन परिभाषाओं का उपयोग (प्रोटोटाइप-प्रारूप पैरामीटर प्रकार और पहचानकर्ता घोषणाकर्ता नहीं) एक अप्रचलित विशेषता है।

पुरानी शैली का मतलब K & R शैली है

उदाहरण:

घोषणा: int old_style();

परिभाषा:

int old_style(a, b)
    int a; 
    int b;
{
     /* something to do */
}

16

C मान लेता है intयदि फ़ंक्शन रिटर्न प्रकार और पैरामीटर सूची पर कोई प्रकार नहीं दिया गया है । केवल इस नियम के लिए अजीब चीजों का पालन करना संभव है।

एक फ़ंक्शन परिभाषा इस तरह दिखती है।

int func(int param) { /* body */}

यदि इसका एक प्रोटोटाइप आप लिखते हैं

int func(int param);

प्रोटोटाइप में आप केवल मापदंडों के प्रकार को निर्दिष्ट कर सकते हैं। पैरामीटर्स का नाम अनिवार्य नहीं है। इसलिए

int func(int);

इसके अलावा, यदि आप पैरामीटर प्रकार निर्दिष्ट नहीं करते हैं, लेकिन नाम intप्रकार के रूप में माना जाता है।

int func(param);

यदि आप आगे बढ़ते हैं, तो निम्नलिखित कार्य भी होते हैं।

func();

int func()जब आप लिखते हैं तो कंपाइलर मान जाता है func()। लेकिन func()एक फंक्शन बॉडी के अंदर न रखें । यह एक फ़ंक्शन कॉल होगा


3
एक खाली पैरामीटर सूची अंतर्निहित int प्रकार से संबंधित नहीं है। int func()का निहित रूप नहीं है int func(int)
जॉन बार्थोलोम्यू

11

जैसा कि @ कृष्णभद्र ने कहा, अन्य उपयोगकर्ताओं की सभी पिछली प्रतिक्रियाओं की सही व्याख्या है, और मैं सिर्फ कुछ बिंदुओं का अधिक विस्तृत विश्लेषण करना चाहता हूं।

एएनएसआई-सी के रूप में ओल्ड-सी में " अप्रतिष्ठित औपचारिक पैरामीटर ", अपने कार्य रजिस्टर या निर्देश की गहराई क्षमता (छाया रजिस्टर या निर्देश संचयी चक्र) का एक आयाम लें, एक 8bit MPU में, एक 1616 में एक int16 होगा MPU और इतने पर एक int16 हो जाएगा, मामले में 64bit आर्किटेक्चर जैसे विकल्प चुनने के लिए चुन सकते हैं: -m32।

हालांकि यह उच्च स्तर पर सरल कार्यान्वयन लगता है, कई मापदंडों को पास करने के लिए, कंट्रोल डिमिनेशन डेटा टाइप चरण में प्रोग्रामर का काम अधिक मांग बन जाता है।

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

लेकिन यह ध्यान दिया जाना चाहिए कि सबसे आधुनिक संकलक, दो प्रकार के मापदंडों की घोषणा के बीच कोई अंतर नहीं करते हैं।

लिनक्स के तहत जीसीसी के साथ एक संकलन के उदाहरण:

main.c

main2.c

main3.c  
किसी भी मामले में स्थानीय रूप से प्रोटोटाइप का विवरण किसी काम का नहीं है, क्योंकि इस प्रोटोटाइप के संदर्भ में मापदंडों के बिना कोई कॉल नहीं है। यदि आप सिस्टम का उपयोग "अनपेक्षित औपचारिक पैरामीटर" के साथ करते हैं, तो एक बाहरी कॉल के लिए, एक घोषणात्मक प्रोटोटाइप डेटा प्रकार उत्पन्न करने के लिए आगे बढ़ें।

ऐशे ही:

int myfunc(int param);

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

1
मुझे पूरा यकीन है कि अनिर्दिष्ट रिटर्न प्रकार हमेशा होता है int, जो आम तौर पर या तो काम-रजिस्टर आकार या 16 बिट्स होता है, जो भी छोटा होता है।
सुपरकैट

@ सुपरफ़ैट +1 सही कटौती, आप सही हैं! यह वही है जो मैं ऊपर चर्चा करता हूं, डिफ़ॉल्ट रूप से निर्दिष्ट आर्किटेक्चर के लिए डिज़ाइन किया गया एक कंपाइलर, हमेशा प्रश्न में सीपीयू / एमपीयू के कार्य-रजिस्टर के आकार को प्रतिबिंबित करता है, इसलिए एक एम्बेडेड वातावरण में, विभिन्न री-टाइपिंग रणनीति हैं realtime OS, एक कंपाइलर लेयर (stdint.h) में, या पोर्टेबिलिटी लेयर में, जो पोर्टेबल को कई अन्य आर्टक्वेक्चर में समान OS बनाता है, और CPU / MPU के विशिष्ट प्रकारों (जैसे, लंबे, लंबे इत्यादि) को अलाइनमेंट द्वारा प्राप्त किया जाता है। जेनेरिक सिस्टम प्रकार u8, u16, u32 के साथ।
RTOSkit

@supercat ऑपरेटिंग सिस्टम या विशिष्ट संकलक द्वारा दिए गए नियंत्रण प्रकारों के बिना, आपको विकास के समय में थोड़ा सा ध्यान देने की आवश्यकता है, और, आप यह सुनिश्चित करते हैं कि सभी "अप्रयुक्त असाइनमेंट" आपके एप्लिकेशन डिज़ाइन के साथ संरेखित हैं, इससे पहले "खोजने का आश्चर्य 16bit int "और" 32bit int "नहीं।
RTOSkit

@RTOSkit: आपका उत्तर बताता है कि 8-बिट प्रोसेसर पर डिफ़ॉल्ट प्रकार एक Int8 होगा। मैं PICmicro ब्रांड आर्किटेक्चर के लिए कुछ सी-ईश कंपाइलर को याद करता हूं जहां वह मामला था, लेकिन मुझे नहीं लगता कि सी मानक जैसा दिखने वाला कुछ भी कभी भी एक intप्रकार की अनुमति देता है जो रेंज में सभी मान रखने में सक्षम नहीं था - 32767 से +32767 (नोट -32768 की आवश्यकता नहीं है) और सभी charमूल्यों को रखने में भी सक्षम है (इसका अर्थ है कि यदि char16 बिट्स हैं, तो या तो इसे हस्ताक्षरित intहोना चाहिए या बड़ा होना चाहिए)।
सुपरकैट

5

पैरामीटर प्रकार के बारे में, यहां पहले से ही सही उत्तर हैं, लेकिन यदि आप इसे संकलक से सुनना चाहते हैं तो आप कुछ झंडे जोड़ने की कोशिश कर सकते हैं (झंडे लगभग हमेशा एक अच्छा विचार हैं)।

अपने प्रोग्राम का उपयोग करके gcc foo.c -Wextraमुझे प्राप्त करना:

foo.c: In function func’:
foo.c:5:5: warning: type of param defaults to int [-Wmissing-parameter-type]

इसके लिए अजीब -Wextraनहीं है clang(यह -Wmissing-parameter-typeकिसी कारण से नहीं पहचाना जाता है, शायद ऊपर वर्णित ऐतिहासिक लोगों के लिए) लेकिन -pedanticकरता है:

foo.c:5:10: warning: parameter 'param' was not declared, 
defaulting to type 'int' [-pedantic]
int func(param)
         ^
1 warning generated.

और प्रोटोटाइप मुद्दे के लिए जैसा कि ऊपर कहा गया है, int func()तब तक मनमाने ढंग से मापदंडों को संदर्भित करता है जब तक कि आप इसे विशिष्ट रूप से परिभाषित नहीं करते हैं int func(void)जो तब आपको त्रुटियों को उम्मीद के मुताबिक देगा:

foo.c: In function func’:
foo.c:6:1: error: number of arguments doesnt match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function main’:
foo.c:12:5: error: too many arguments to function func
foo.c:5:5: note: declared here

या के clangरूप में:

foo.c:5:5: error: conflicting types for 'func'
int func(param)
    ^
foo.c:3:5: note: previous declaration is here
int func(void);
    ^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
    int bla = func(10);
              ~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.

3

यदि फ़ंक्शन घोषणा में कोई पैरामीटर नहीं है अर्थात खाली है तो यह अनिर्दिष्ट संख्या में तर्क ले रहा है। यदि आप इसे बिना तर्क के लेना चाहते हैं तो इसे इसमें बदल दें:

int func(void);

1
"यदि फ़ंक्शन प्रोटोटाइप में कोई पैरामीटर नहीं है" तो यह फ़ंक्शन प्रोटोटाइप नहीं है, बस एक फ़ंक्शन घोषणा है।
पुतला

@effeffe ने तय किया कि। मुझे नहीं पता था कि इस सवाल पर बहुत ध्यान दिया जाएगा;)
पीपी

3
क्या "फ़ंक्शन घोषणा" के लिए "फ़ंक्शन प्रोटोटाइप" सिर्फ एक वैकल्पिक (संभवतः पुराने जमाने की) अभिव्यक्ति नहीं है?
जियोर्जियो

@ जिओर्जियो IMO, दोनों सही हैं। "फ़ंक्शन प्रोटोटाइप" को "फ़ंक्शन परिभाषा" से मेल खाना चाहिए। मुझे शायद लगता है कि पुतले का मतलब सवाल में घोषणा है और मेरे कहने का मतलब मेरे जवाब में है।
पीपी

@ जियोर्जियो नं, फ़ंक्शन घोषणा वापसी प्रकार के मूल्य, पहचानकर्ता और एक वैकल्पिक पैरामीटर सूची द्वारा की जाती है; फ़ंक्शन प्रोटोटाइप एक पैरामीटर सूची के साथ फ़ंक्शन घोषणा हैं।
पंद्रह

0

यही कारण है कि मैं आमतौर पर लोगों को अपना कोड संकलित करने की सलाह देता हूं:

cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition

ये झंडे कुछ बातों को लागू करते हैं:

  • -विस्मिंग-चर-घोषणाएँ: पहले एक प्रोटोटाइप प्राप्त किए बिना गैर-स्थिर फ़ंक्शन घोषित करना असंभव है। इससे यह अधिक संभावना है कि हेडर फ़ाइल में एक प्रोटोटाइप वास्तविक परिभाषा के साथ मेल खाता है। वैकल्पिक रूप से, यह लागू करता है कि आप स्थिर कीवर्ड को उन कार्यों में जोड़ते हैं जिन्हें सार्वजनिक रूप से दिखाई देने की आवश्यकता नहीं है।
  • निर्णय-चर-घोषणाएँ: प्रोटोटाइप को तर्कों को ठीक से सूचीबद्ध करना होगा।
  • -वॉल्ड-स्टाइल-डेफिनिशन: फंक्शन डेफिनिशन को भी तर्कों को ठीक से सूचीबद्ध करना होगा।

इन झंडे का उपयोग डिफ़ॉल्ट रूप से बहुत सारे ओपन सोर्स प्रोजेक्ट में भी किया जाता है। उदाहरण के लिए, आपके मेकफाइल में WARNS = 6 के साथ निर्माण करते समय FreeBSD के पास ये ध्वज सक्षम हैं।

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