क्या हालत के हिस्से में कार्य एक बुरा अभ्यास है?


35

मान लेते हैं कि मैं एक फ़ंक्शन लिखना चाहता हूं जो सी में दो तारों को मिलाता है। जिस तरह से मैं इसे लिखूंगा वह है:

void concat(char s[], char t[]){
    int i = 0;
    int j = 0;

    while (s[i] != '\0'){
        i++;
    }

    while (t[j] != '\0'){
        s[i] = t[j];
        i++;
        j++;
    }

    s[i] = '\0';

}

हालांकि, अपनी पुस्तक में के एंड आर ने इसे अलग तरीके से लागू किया, विशेष रूप से जितना संभव हो उतना लूप के स्थिति भाग में शामिल किया गया:

void concat(char s[], char t[]){
    int i, j;
    i = j = 0;
    while (s[i] != '\0') i++;

    while ((s[i++]=t[j++]) != '\0');

}

कौन सा तरीका पसंद किया जाता है? क्या यह K & R के कोड को लिखने के लिए प्रोत्साहित या हतोत्साहित करता है? मेरा मानना ​​है कि मेरे संस्करण को अन्य लोगों द्वारा पढ़ना आसान होगा।


38
मत भूलना, के एंड आर को पहली बार 1978 में प्रकाशित किया गया था। तब से हम कैसे कोड करते हैं, इसमें कुछ छोटे बदलाव हुए हैं।
corsiKa

28
टेलीप्रिंटर्स और लाइन-ओरिएंटेड संपादकों के दिनों में पठनीयता बहुत अलग थी। एक ही लाइन पर उस सभी सामान को निस्तब्धता अधिक पठनीय हुआ करती थी।
user2357112

15
मैं हैरान हूं कि उनके पास कुछ चीज़ों के बजाय '\ _' के सूचक और तुलनाएं हैं while (*s++ = *t++); (मेरी सी बहुत जंग लगी है, क्या मुझे ऑपरेटर पूर्वता के लिए वहां परेंस की आवश्यकता है?) क्या के एंड आर ने अपनी पुस्तक का एक नया संस्करण जारी किया? उनकी मूल पुस्तक में बहुत संक्षिप्त और मुहावरेदार कोड थे।
user949300

4
पठनीयता एक बहुत ही निजी चीज है - यहां तक ​​कि टेलेटिप के दिनों में भी। अलग-अलग लोग अलग-अलग स्टाइल पसंद करते हैं। क्रैमिंग के बहुत सारे निर्देश कोड पीढ़ी के साथ करना था। उन दिनों में, कुछ निर्देश सेट करते हैं (जैसे डेटा जनरल) एक निर्देश में कई कार्यों को रटना सकता है। इसके अलावा, 80 के दशक की शुरुआत में, एक मिथक था कि कोष्ठक का उपयोग करने से अधिक निर्देश उत्पन्न होते हैं। मुझे कोड समीक्षक को यह साबित करने के लिए कोडांतरक उत्पन्न करना था कि यह एक मिथक था।
कप 10

10
ध्यान दें कि दो कोड ब्लॉक समकक्ष नहीं हैं। पहला कोड ब्लॉक ( पहले निकास) '\0'से समाप्ति की प्रतिलिपि नहीं देगा । यह परिणामी स्ट्रिंग को एक समाप्ति के बिना छोड़ देगा (जब तक कि मेमोरी स्थान पहले से ही शून्य नहीं था)। दूसरा कोड ब्लॉक लूप से बाहर निकलने से पहले समाप्त होने की प्रतिलिपि बना देगा । twhiles'\0''\0'while
मकेन

जवाबों:


80

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

कोई भी मूर्ख कोड लिख सकता है जिसे कंप्यूटर समझ सकता है। अच्छे प्रोग्रामर कोड लिखते हैं जो मनुष्य समझ सकते हैं। (एम। फाउलर)

तो, कोई संदेह नहीं है, मैं विकल्प ए के लिए जाऊंगा और यह मेरा निश्चित जवाब है।


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

26
@MilesRout है। किसी भी कोड के साइड इफेक्ट होने के साथ कुछ गड़बड़ है जहां आप इसकी उम्मीद नहीं करते हैं, अर्थात् फ़ंक्शन तर्क या सशर्त मूल्यांकन करना। यह भी उल्लेख नहीं है कि if (a=b)आसानी से गलती हो सकती है if (a==b)
आर्थर हैवेलिस

12
@ ल्यूक: "मेरी आईडीई एक्स को साफ कर सकती है, इसलिए यह कोई समस्या नहीं है" बल्कि असंबद्ध है। यदि यह कोई समस्या नहीं है, तो IDE इसे "ठीक करना" क्यों इतना आसान बनाता है?
केविन

6
@ArthurHavlicek मैं आपके सामान्य बिंदु से सहमत हूं, लेकिन सशर्त में दुष्प्रभावों के साथ कोड वास्तव में इतना असामान्य नहीं है: while ((c = fgetc(file)) != EOF)जैसा कि मेरे दिमाग में आता है।
डैनियल जर्स

3
+1 "यह मानते हुए कि डिबगिंग पहले स्थान पर प्रोग्राम लिखने के रूप में दोगुना कठिन है, यदि आप उतने ही चतुर हैं जितना कि आप इसे लिखते समय हो सकते हैं, तो आप इसे कैसे डिबग करेंगे?" BWKernighan
क्रिस्टोफ

32

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

प्रोग्रामर के लिए जो सी के साथ शुरू नहीं हुआ था, पहले संस्करण को समझना आसान है, उन कारणों के लिए जिन्हें आप पहले से जानते हैं।

उन लोगों के लिए जो सी की उस शैली के साथ बड़े हुए हैं, दूसरा संस्करण समझने में आसान हो सकता है: उनके लिए, यह समान रूप से समझने योग्य है कि कोड क्या करता है, उनके लिए यह कम सवाल छोड़ता है कि यह किस तरह से लिखा गया है, और उनके लिए , कम ऊर्ध्वाधर स्थान का मतलब है कि स्क्रीन पर अधिक संदर्भ प्रदर्शित किया जा सकता है।

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


14

संपादित करें: लाइन s[i] = '\0';को पहले संस्करण में जोड़ा गया था, जिससे नीचे दिए गए संस्करण 1 में वर्णित किया गया है, इसलिए यह प्रश्न के कोड के वर्तमान संस्करण पर लागू नहीं होता है।

दूसरे संस्करण के सही होने का विशिष्ट लाभ है , जबकि पहला नहीं है - यह लक्ष्य स्ट्रिंग को सही ढंग से समाप्त नहीं करता है।

"स्थिति में असाइनमेंट " बहुत संक्षिप्त रूप से "चरित्र की जांच करने से पहले प्रत्येक चरित्र की नकल करने की अनुमति देता है। । यदि आप पहले संस्करण का उपयोग करने पर जोर देते हैं, तो आपको या तो करना होगा

  1. दूसरे लूप के अंत के बाद शून्य-समाप्ति जोड़ें (अधिक कोड जोड़कर, लेकिन आप बहस कर सकते हैं कि readabiliy इसे सार्थक बनाता है) या
  2. लूप बॉडी को "पहले असाइन करें, फिर या तो चेक करें या असाइन किए गए चार्ज़ को सेव करें, फिर इन्क्रीमेंट इंडेक्स" को बदलें। लूप के बीच में स्थिति की जांच करने का मतलब है कि लूप से बाहर निकलना (स्पष्टता को कम करना, अधिकांश शुद्धतावादियों द्वारा पर आधारित)। नियत चार को बचाने का मतलब होगा कि एक अस्थायी चर (स्पष्टता और दक्षता को कम करना)। उन दोनों ने मेरी राय में लाभ का सफाया कर दिया।

सही पठनीय और संक्षिप्त से बेहतर है।
20:

5

ट्यूलेंस कोर्डोवा और एचवीडी के जवाब स्पष्टता / पठनीयता के पहलुओं को काफी अच्छी तरह से कवर करते हैं। मुझे परिस्थितियों में असाइनमेंट के पक्ष में एक और कारण के रूप में स्कूपिंग में फेंक देना चाहिए । शर्त में घोषित एक चर केवल उस कथन के दायरे में उपलब्ध है। आप दुर्घटना के बाद उस चर का उपयोग नहीं कर सकते। के लिए पाश उम्र के लिए यह कर दिया गया है। और यह काफी महत्वपूर्ण है कि आगामी C ++ 17 यदि और स्विच के लिए एक समान सिंटैक्स पेश करता है :

if (int foo = bar(); foo > 42) {
    do_stuff();
}

foo = 23;   // compiler error: foo is not in scope

3

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

if ((a = f()) != NULL)
    ...

उदाहरण के लिए (या जबकि)।


7
इसमें कुछ गड़बड़ है; `! = NULL` और उसके परिजन सी हालत में हैं, बस ऐसे डेवलपर्स को गिरवी रखना है जो किसी मूल्य के सही या गलत होने (या इसके विपरीत) की अवधारणा के साथ सहज नहीं हैं।
जोनाथन कास्ट

1
@jcast नहीं, इसे शामिल करना अधिक स्पष्ट है != NULL
माइल्स राउत

1
नहीं, यह कहना अधिक स्पष्ट है (x != NULL) != 0। आखिरकार, यह वही है जो सी वास्तव में जाँच रहा है, है ना?
जोनाथन

@jcast नहीं, यह नहीं है। यह जाँचना कि क्या कुछ असत्य के लिए असमान है, यह नहीं है कि आप किसी भी भाषा में सशर्त कैसे लिखते हैं।
माइल्स राउत

"यह जाँचना कि क्या कुछ असत्य के लिए असमान है, यह नहीं है कि आप किसी भी भाषा में सशर्त कैसे लिखते हैं।" ठीक ठीक।
जोनाथन

2

K & R के दिनों में

  • 'C' पोर्टेबल असेंबली कोड था
  • इसका उपयोग प्रोग्रामर्स द्वारा किया गया था जो विधानसभा कोड में सोचते थे
  • कंपाइलर ने ज्यादा अनुकूलन नहीं किया
  • अधिकांश कंप्यूटरों में "जटिल निर्देश सेट" थे, उदाहरण के लिए while ((s[i++]=t[j++]) != '\0')अधिकांश सीपीयू पर एक निर्देश पर मैप किया जाएगा (मुझे उम्मीद है कि दिसंबर VAC)

वहाँ दिन

  • C कोड पढ़ने वाले अधिकांश लोग असेंबली कोड प्रोग्रामर नहीं होते हैं
  • C कंपाइलर बहुत सारे ऑप्टिमाइज़ेशन करते हैं, इसलिए कोड को पढ़ने में जितना सरल है, उसी मशीन कोड में अनुवादित होने की संभावना है।

(हमेशा ब्रेसिज़ का उपयोग करने पर एक नोट - कोड का पहला सेट कुछ "अनावश्यक" होने के कारण अधिक स्थान लेता है {}, मेरे अनुभव में ये अक्सर कोड को रोकते हैं जो बुरी तरह से संकलक से विलय कर दिया गया है और गलत के साथ त्रुटियों की अनुमति देता है "?" उपकरण द्वारा पता लगाया गया।)

हालाँकि पुराने दिनों में कोड का दूसरा संस्करण पढ़ा होगा। (अगर मैं सही हो गया!)

concat(char* s, char *t){      
    while (*s++);
    --s;
    while (*s++=*t++);
}

2

यहां तक ​​कि यह सब करने में सक्षम होना भी बहुत बुरा विचार है। यह बोलचाल की भाषा में "द वर्ल्ड्स लास्ट बग" के रूप में जाना जाता है:

if (alert = CODE_RED)
{
   launch_nukes();
}

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


इन चेतावनी से पहले, हम लिखेंगे CODE_RED = alertताकि यह एक संकलक त्रुटि दे।
इयान

4
@ इयान योडा कंडीशंस जिसे कहा जाता है। मुश्किल से वे पढ़ते हैं। दुर्भाग्य से उनके लिए आवश्यकता है।
मेसन व्हीलर

एक बहुत ही संक्षिप्त परिचयात्मक "अवधि के लिए इस्तेमाल होने" के बाद, योदा की स्थिति सामान्य लोगों की तुलना में पढ़ने के लिए कठिन नहीं है। कभी-कभी वे अधिक पठनीय होते हैं । उदाहरण के लिए, यदि आपके पास ifs / Persifs का अनुक्रम है, तो उच्च जोर देने के लिए बाईं ओर परीक्षण की जा रही स्थिति एक मामूली सुधार IMO है।
user949300

2
@ user949300 दो शब्द: स्टॉकहोम सिंड्रोम: पी
मेसन व्हीलर

2

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

उदाहरण के लिए, नेटबीन्स द्वारा निम्नलिखित अभिव्यक्ति पर प्रकाश डाला गया है :

if($a = someFunction())

"आकस्मिक कार्य" के आधार पर।

यहाँ छवि विवरण दर्ज करें

स्पष्ट रूप से नेटबीन्स को यह बताने के लिए कि "हाँ, मैं वास्तव में ऐसा करने का मतलब था ...", अभिव्यक्ति को पेरेंटिस के सेट में लपेटा जा सकता है।

if(($a = someFunction()))

यहाँ छवि विवरण दर्ज करें

दिन के अंत में, यह सभी कंपनी शैली के दिशा निर्देशों और विकास प्रक्रिया को सुविधाजनक बनाने के लिए आधुनिक उपकरणों की उपलब्धता के लिए उबालता है।

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