संकलक गुम अर्धविराम की रिपोर्ट क्यों नहीं करता है?


115

मेरा यह सरल कार्यक्रम है:

#include <stdio.h>

struct S
{
    int i;
};

void swap(struct S *a, struct S *b)
{
    struct S temp;
    temp = *a    /* Oops, missing a semicolon here... */
    *a = *b;
    *b = temp;
}

int main(void)
{
    struct S a = { 1 };
    struct S b = { 2 };

    swap(&a, &b);
}

जैसा कि ideone.com पर देखा गया है, यह एक त्रुटि देता है:

prog.c: In function 'swap':
prog.c:12:5: error: invalid operands to binary * (have 'struct S' and 'struct S *')
     *a = *b;
     ^

संकलक लापता अर्धविराम का पता क्यों नहीं लगाता है?


नोट: यह प्रश्न और इसका उत्तर इस प्रश्न से प्रेरित है । जबकि वहाँ हैं अन्य प्रश्न इस के समान, मैं कुछ भी सी भाषा है जो इस और संबंधित त्रुटियों क्या खड़ी कर रहा है है की मुक्त रूप क्षमता का उल्लेख नहीं मिला।


16
इस पोस्ट ने क्या प्रेरित किया?
आर साहू

10
@TavianBarnes की खोज। इस तरह के मुद्दे की खोज करते समय दूसरा प्रश्न खोज योग्य नहीं है। इसे इस तरह से संपादित किया जा सकता है, लेकिन इसके लिए थोड़ा बहुत बदलाव करने की आवश्यकता होगी, जिससे यह एक अलग प्रश्न बन जाएगा।
कुछ प्रोग्रामर ने

4
@TavianBarnes: मूल प्रश्न त्रुटि के लिए पूछ रहा था। यह प्रश्न पूछ रहा है कि कंपाइलर को क्यों लगता है (ओपी कम से कम) त्रुटि के स्थान को गलत बताने के लिए।
टोनीके

80
इंगित करने के लिए बिंदु: यदि एक संकलक व्यवस्थित रूप से लापता अर्ध-कॉलनों का पता लगा सकता है, तो भाषा को शुरू करने के लिए अर्ध-कॉलनों की आवश्यकता नहीं होगी।
बजे यूरो माइक्रोएली

5
संकलक का काम त्रुटि की रिपोर्ट करना है। यह पता लगाना आपका काम है कि त्रुटि को ठीक करने के लिए क्या बदलना है।
डेविड श्वार्ट्ज

जवाबों:


213

सी एक स्वतंत्र रूप है भाषा है। इसका मतलब है कि आप इसे कई तरीकों से प्रारूपित कर सकते हैं और यह अभी भी एक कानूनी कार्यक्रम होगा।

उदाहरण के लिए एक बयान की तरह

a = b * c;

की तरह लिखा जा सकता है

a=b*c;

या पसंद है

a
=
b
*
c
;

तो जब संकलक लाइनों को देखते हैं

temp = *a
*a = *b;

यह सोचता है कि इसका मतलब है

temp = *a * a = *b;

यह निश्चित रूप से एक मान्य अभिव्यक्ति नहीं है और संकलक लापता अर्धविराम के बजाय इसके बारे में शिकायत करेगा। इसका कारण यह मान्य नहीं है क्योंकि aएक संरचना के लिए एक सूचक है, इसलिए *a * aएक संरचना उदाहरण को गुणा करने की कोशिश कर रहा है (*a एक सूचक ) के साथ एक )a

जबकि कंपाइलर लापता अर्धविराम का पता नहीं लगा सकता है, यह गलत लाइन पर पूरी तरह से असंबंधित त्रुटि की भी रिपोर्ट करता है। यह नोटिस करना महत्वपूर्ण है क्योंकि आप जिस लाइन पर त्रुटि की सूचना देते हैं, वहां कोई भी चीज नहीं है, वहां कोई त्रुटि नहीं है। कभी-कभी इस तरह की समस्याओं को आपको पहले देखने की आवश्यकता होगी लाइनों को देखने की कि क्या वे ठीक हैं और बिना त्रुटियों के हैं।

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

और कभी-कभी यह और भी बदतर हो जाता है: यदि आप दो (या अधिक) हेडर फ़ाइलों को शामिल करते हैं, और पहले वाले में एक अधूरा घोषणा शामिल है, तो संभवत: सिंटैक्स त्रुटि दूसरी हेडर फ़ाइल में इंगित की जाएगी।


इससे संबंधित फॉलो-अप त्रुटियों की अवधारणा है । आम तौर पर लापता अर्धविराम के कारण कुछ त्रुटियां, कई त्रुटियों के रूप में रिपोर्ट की जाती हैं। यही कारण है कि त्रुटियों को ठीक करते समय ऊपर से शुरू करना महत्वपूर्ण है, क्योंकि पहली त्रुटि को ठीक करने से कई त्रुटियां गायब हो सकती हैं।

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


16
ओवरलोड होने पर C ++ में, एक वैध अभिव्यक्ति temp = *a * a = *b हो सकती है operator*। (इस सवाल को "C" के रूप में टैग किया गया है।)
dan04

13
@ dan04: अगर किसी ने वास्तव में ऐसा किया है ... NOPE!
केविन

2
पहली सूचित त्रुटि के साथ शुरू होने के बारे में सलाह के लिए +1; और (बी) त्रुटि की सूचना दी गई है, जहां से पीछे की ओर देख रहे हैं। आप जानते हैं कि आप एक वास्तविक प्रोग्रामर हैं जब आप स्वचालित रूप से लाइन पर नज़र डालते हैं, जहाँ एक त्रुटि की सूचना दी जाती है :-)
ट्रीपहाउंड

@TripeHound ESPECIALLY, जब बहुत बड़ी संख्या में त्रुटियां हों, या पहले से संकलित की गई पंक्तियां त्रुटियां फेंक रही हों ...
टिन जादूगर

1
जैसा कि आम तौर पर मेटा के साथ होता है, किसी ने पहले ही पूछा - meta.stackoverflow.com/questions/266663/…
StoryTeller - Unslander Monica

27

संकलक लापता अर्धविराम का पता क्यों नहीं लगाता है?

याद करने के लिए तीन चीजें हैं।

  1. सी में लाइन एंडिंग केवल साधारण व्हाट्सएप हैं।
  2. *C में एक unary और एक बाइनरी ऑपरेटर दोनों हो सकते हैं। एक यूनिरी ऑपरेटर के रूप में इसका अर्थ है "डीरेफेरेंस", एक बाइनरी ऑपरेटर के रूप में इसका अर्थ है "गुणा"।
  3. यूनीरी और बाइनरी ऑपरेटरों के बीच का अंतर उस संदर्भ से निर्धारित होता है जिसमें उन्हें देखा जाता है।

इन दो तथ्यों का परिणाम है जब हम पार्स करते हैं।

 temp = *a    /* Oops, missing a semicolon here... */
 *a = *b;

पहले और आखिरी *की व्याख्या एकात्मक के रूप में की जाती है लेकिन दूसरी *की व्याख्या द्विआधारी के रूप में की जाती है। एक वाक्यविन्यास परिप्रेक्ष्य से, यह ठीक दिखता है।

यह पार्स करने के बाद ही होता है जब कंपाइलर अपने ऑपरेंड प्रकारों के संदर्भ में ऑपरेटरों की व्याख्या करने की कोशिश करता है कि कोई त्रुटि दिखाई देती है।


4

ऊपर कुछ अच्छे उत्तर, लेकिन मैं विस्तार से बताऊंगा।

temp = *a *a = *b;

यह वास्तव में का एक मामला है x = y = z;जहां दोनों xऔर yके मूल्य को आवंटित कर रहे हैंz

आप जो कह रहे हैं, वह है the contents of address (a times a) become equal to the contents of b, as does temp

संक्षेप में, *a *a = <any integer value>एक मान्य कथन है। जैसा कि पहले बताया गया है, पहला *एक पॉइंटर का सूचक है, जबकि दूसरा दो मूल्यों को गुणा करता है।


3
डेरेफेरेंस प्राथमिकता लेता है, इसलिए यह (ए) पते की सामग्री (पॉइंटर टू ए) है। आप बता सकते हैं, क्योंकि संकलित त्रुटि "बाइनरी * के लिए अमान्य ऑपरेंड्स ('स्ट्रक्चर एस' और 'स्ट्रक्चर एस *') कहती है" जो कि दो प्रकार के होते हैं।
डैस्कैंडी

मैं पूर्व C99 को कोड करता हूं, इसलिए कोई बूल्स :-) लेकिन आप एक अच्छा बिंदु (+1) बनाते हैं, हालांकि असाइनमेंट का क्रम वास्तव में मेरे उत्तर का बिंदु नहीं था
मावग का कहना है कि मोनिका

1
लेकिन इस मामले में, yएक चर भी नहीं है, यह अभिव्यक्ति है *a *a, और आप गुणा के परिणाम को निर्दिष्ट नहीं कर सकते।
बर्मार

@ बरमार वास्तव में, लेकिन संकलक अभी तक नहीं मिला है, यह पहले से ही तय कर चुका है कि असाइनमेंट ऑपरेटर को देखने से पहले "बाइनरी *" को ऑपरेंड अमान्य हैं।
प्लगवेट

3

अधिकांश संकलक स्रोत फ़ाइलों को क्रम में पार्स करते हैं, और उस रेखा की रिपोर्ट करते हैं जहां उन्हें पता चलता है कि कुछ गलत था। आपके C प्रोग्राम की पहली 12 लाइनें एक वैध (त्रुटि रहित) C प्रोग्राम की शुरुआत हो सकती हैं। आपके प्रोग्राम की पहली 13 लाइनें नहीं हो सकती हैं। कुछ कंपाइलर उन चीजों का स्थान नोट करेंगे, जिनका वे सामना करते हैं, जो स्वयं और उनमें से कोई भी त्रुटि नहीं है, और अधिकांश मामलों में बाद में कोड में त्रुटियों को ट्रिगर नहीं किया जाएगा, लेकिन कुछ और के साथ संयोजन में मान्य नहीं हो सकता है। उदाहरण के लिए:

int foo;
...
float foo;

int foo;अपने आप से घोषणा पूरी तरह से ठीक होगी। इसी तरह घोषणा float foo;। कुछ कंपाइलर लाइन नंबर को रिकॉर्ड कर सकते हैं, जहां पहली घोषणा दिखाई दी थी, और प्रोग्रामर को उन मामलों की पहचान करने में मदद करने के लिए उस लाइन के साथ एक सूचना संदेश जोड़ते हैं, जहां पहले की परिभाषा वास्तव में गलत है। कंपाइलर लाइन नंबर को किसी चीज़ से जुड़ा हुआ भी रख सकते हैं do, जिसे रिपोर्ट किया जा सकता है अगर संबंधित whileसही जगह पर दिखाई नहीं देता है। ऐसे मामलों के लिए जहां समस्या की संभावित स्थिति तुरंत उस रेखा से पहले होगी जहां त्रुटि का पता चला है, हालांकि, आमतौर पर संकलनकर्ता स्थिति के लिए एक अतिरिक्त रिपोर्ट जोड़ने से परेशान नहीं होते हैं।

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