c - उस लूप में बुलाए गए फ़ंक्शन के भीतर से एक लूप से बाहर निकलना




for-loop break (10)

(नोट: प्रश्न को संपादित किया गया है क्योंकि मैंने मूल रूप से यह लिखा था)

सी संकलित होने के तरीके के कारण यह पता होना चाहिए कि समारोह कहां से तोड़ना है। चूंकि आप इसे कहीं से भी कॉल कर सकते हैं, या यहां तक ​​कि कहीं भी ब्रेक का कोई मतलब नहीं है, तो आप break; नहीं ले सकते break; अपने समारोह में बयान और यह इस तरह काम करते हैं।

अन्य उत्तरों ने फ़ंक्शन से #define या longjumping (!) का उपयोग करके वैश्विक चर सेट करने जैसे भयानक समाधान सुझाए हैं। ये बेहद खराब समाधान हैं। इसके बजाए, आपको उस समाधान का उपयोग करना चाहिए जिसे आपने अपने शुरुआती पैराग्राफ में गलत तरीके से खारिज कर दिया है और अपने फ़ंक्शन से एक मान वापस कर दिया है जो इस स्थिति में एक break ट्रिगर करना चाहता है और इस तरह कुछ करता है:

#include <stdbool.h>

bool checkAndDisplay(int n)
{
    printf("%d\n", n);
    return (n == 14);
}

int main(void) {
    for (int i = 0; i <= 100; i++) {
        if (checkAndDisplay(i))
            break;
    }
    return 0;
}

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

आप एक टिप्पणी में छिपे हुए हैं, कि आपको शून्य वापसी का उपयोग करना होगा, यह कोई समस्या नहीं है, बस पॉइंटर के रूप में ब्रेक पैरामीटर को पास करें:

#include <stdbool.h>

void checkAndDisplay(int n, bool* wantBreak)
{
    printf("%d\n", n);
    if (n == 14)
        wantBreak = true;
}

int main(void) {
    bool wantBreak = false;
    for (int i = 0; i <= 100; i++) {
        checkAndDisplay(i, &wantBreak);
        if (wantBreak)
            break;
    }
    return 0;
}

चूंकि आपके पैरामीटर निश्चित प्रकार हैं, मेरा सुझाव है कि आप संकेतक में से किसी एक को पॉइंटर में पास करने के लिए एक कास्ट का उपयोग करें, उदाहरण के लिए foo(a, b, (long)&out);

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

void foo (int passV, int aVal, long bVal)

मुझे पता है कि रिटर्न वैल्यू का उपयोग नहीं करना बहुत बुरा अभ्यास है लेकिन असल परिस्थितियों में मुझे मजबूर करना पड़ता है, इसलिए कृपया मेरे साथ सहन करें।

निम्नलिखित उदाहरण पर विचार करें:

#include <stdio.h>

void foo (int a) {
    printf("a: %d", a);
    break;
}

int main(void) {
    for (int i = 0; i <= 100; i++) {
        foo(i);
    }
    return 0;
}

अब यह संकलित नहीं है। इसके बजाए, मुझे संकलन त्रुटि निम्नानुसार मिलती है:

prog.c: फ़ंक्शन 'foo' में: prog.c: 6: 2: त्रुटि: ब्रेक स्टेटमेंट लूप या स्विच ब्रेक के भीतर नहीं;

मुझे पता है इसका मतलब क्या है (संकलक कहता है कि foo() में ब्रेक लूप के भीतर नहीं है)

अब, ब्रेक स्टेटमेंट के संबंध में मानक से मुझे क्या मिल सकता है यह है:

ब्रेक स्टेटमेंट नियंत्रण के दौरान नियंत्रण, कारण, या स्विच स्टेटमेंट के बाद सबसे ज्यादा संलग्न होने के बाद नियंत्रण को नियंत्रित करता है। वाक्यविन्यास बस टूटना है;

मेरे फ़ंक्शन को ध्यान में रखते हुए लूप के लिए कहा जाता है, क्यों ब्रेक स्टेटमेंट लूप के लिए कहा जाता है? इसके अलावा, क्या फ़ंक्शन वापस लौटने के बिना ऐसा कुछ महसूस करना संभव है?


आप break; उपयोग नहीं कर सकते break; इस तरह, यह लूप के शरीर के अंदर दिखाई देना चाहिए।

ऐसा करने के कई तरीके हैं, लेकिन न ही अनुशंसा की जाती है:

  • आप बाहर exit() फ़ंक्शन के साथ प्रोग्राम से बाहर निकल सकते हैं। चूंकि लूप main() से चलाया जाता है और आप इसके बाद कुछ भी नहीं करते हैं, इसलिए आप इस तरह से हासिल करना संभव है, लेकिन यह एक विशेष मामले के रूप में है।

  • आप फंक्शन कॉल में ग्लोबल वैरिएबल सेट कर सकते हैं और फ़ंक्शन कॉल के बाद लूप में परीक्षण कर सकते हैं। वैश्विक चर का उपयोग आम तौर पर अनुशंसित अभ्यास नहीं है।

  • आप longjmp() setjmp() और longjmp() उपयोग कर सकते हैं, लेकिन यह एक हथौड़ा के साथ एक फ्लाई स्क्वैश करने की कोशिश करने की तरह है, आप अन्य चीजों को तोड़ सकते हैं और फ्लाई को पूरी तरह से याद कर सकते हैं। मैं इस दृष्टिकोण की सिफारिश नहीं करता। इसके अलावा, इसे एक jmpbuf आवश्यकता है जिसे आपको फ़ंक्शन या वैश्विक वैरिएबल के रूप में एक्सेस करना होगा।

एक स्वीकार्य विकल्प एक status वैरिएबल के पते को अतिरिक्त तर्क के रूप में पास करना है: फ़ंक्शन इसे लूप से तोड़ने की आवश्यकता को इंगित करने के लिए सेट कर सकता है।

लेकिन सी में अब तक का सबसे अच्छा दृष्टिकोण निरंतरता के परीक्षण के लिए एक मूल्य लौटा रहा है , यह सबसे अधिक पठनीय है।

आपके स्पष्टीकरण से, आपके पास foo() के लिए स्रोत कोड नहीं है, लेकिन फ़ंक्शन में कुछ स्थितियों का पता लगा सकता है जिसे आप सीधे या अप्रत्यक्ष रूप से संशोधित कर सकते हैं foo() : longjmp() अपने स्थान से कूद जाएगा, आंतरिक के अंदर गहराई से foo() , संभवतः कॉल स्टैक के नीचे कई स्तर, setjmp() स्थान पर, सभी मध्यस्थ कॉल के लिए नियमित फ़ंक्शन निकास कोड को छोड़कर। यदि दुर्घटना से बचने के लिए आपको यह करने की ज़रूरत है, तो longjmp() setjmp() / longjmp() एक समाधान है, लेकिन इससे संसाधनों की रिसाव, अनुपलब्ध प्रारंभिकरण, असंगत स्थिति और अपरिभाषित व्यवहार के अन्य स्रोत जैसे अन्य समस्याएं हो सकती हैं।

ध्यान दें कि आपके लूप के for 101 बार पुनरावृत्ति होगी क्योंकि आप <= ऑपरेटर का उपयोग करते हैं। लूप के for idiomatic for (int i = 0; i < 100; i++) लिए उपयोग करता है ताकि ऊपरी (बहिष्कृत) बाध्य के रूप में दिखाई देने वाले समय की संख्या को फिर से चालू किया जा सके।


आपके अद्यतित प्रश्न के बाद सीमाओं को स्पष्ट रूप से निर्धारित करने के बाद, मैं सुझाव दूंगा कि आप अपने फ़ंक्शन के अंदर पूरे लूप को स्थानांतरित करें और फिर उस फ़ंक्शन के अंदर रिटर्न वैल्यू के साथ दूसरा फ़ंक्शन कॉल करें, उदाहरण के लिए

#include <stdbool.h>

bool foo (int x)
{
    return (x==14);
}

void loopFoo(int passV, int aVal, long bVal)
{
   for (int i = 0; i <= 100; ++i)
   {
       if (foo(x))
           break;
   }
}

यह सीमा के चारों ओर पाने के लिए किसी भी चरम और नाजुक जिमनास्टिक से बचाता है।


इस तरह के मामले में लूप के बजाए && के साथ कई सशर्त बयानों के साथ थोड़ी देर () लूप का उपयोग करने पर विचार करें। यद्यपि आप setjmp और longjmp जैसे कार्यों का उपयोग करके सामान्य नियंत्रण प्रवाह को बदल सकते हैं , लेकिन यह हर जगह खराब अभ्यास माना जाता है। क्यों पता लगाने के लिए आपको इस साइट पर बहुत मुश्किल खोजना नहीं चाहिए। (संक्षेप में यह घुलनशील नियंत्रण प्रवाह बनाने की क्षमता के कारण है जो स्वयं को डीबगिंग या मानव समझ में उधार नहीं देता है)

इस तरह कुछ करने पर भी विचार करें:

int foo (int a) {
    if(a == someCondition) return 0;
    else {
        printf("a: %d", a);
        return 1;
    }
}

int main(void) {
    for (int i = 0; i <= 100; i++) {
        if(!foo(i)) break;
    }
    return 0;
}

इस मामले में, लूप 'foo' से वापस आने वाले एक वास्तविक मूल्य पर निर्भर करता है, जो 'foo' के अंदर की स्थिति को पूरा नहीं करता है, तो लूप तोड़ देगा।

संपादित करें: मैं गेटो, setjmp, longjmp इत्यादि के उपयोग के खिलाफ स्पष्ट रूप से नहीं हूं। लेकिन मुझे लगता है कि इस मामले में इन उपायों का उपयोग किए बिना एक बहुत ही सरल और अधिक संक्षिप्त समाधान उपलब्ध है!


बस एक वैश्विक चर सेट करें और लूप पर जांचें:

#include <stdio.h>

int leave = 0;

void foo (int a) {
    printf("a: %d", a);
    leave = 1;
}

int main(void) {
    for (int i = 0; i <= 100; i++) {
        foo(i);
        if (leave)
          break;
    }
    return 0;
}

मेरा मानना ​​है कि यह संबंधित है कि break स्टेटमेंट का अनुवाद मशीन कोड में कैसे किया जाता है। break स्टेटमेंट को लूप या स्विच के तुरंत बाद लेबल में बिना शर्त शाखा के रूप में अनुवादित किया जाएगा।

mov ECX,5
label1:
  jmp <to next instruction address>  ;break
loop label1
<next instruction>

जबकि लूप के अंदर से foo() को कॉल करने के परिणामस्वरूप कुछ ऐसा होगा

mov ECX,5
label1:
  call <foo address>
loop label1
<next instruction>

और foo पते पर

call <printf address>
jmp <to where?> ;break cannot translate to any address.

यदि आप रिटर्न वैल्यू को संभाल नहीं सकते हैं, तो क्या आप कम से कम फ़ंक्शन में पैरामीटर जोड़ सकते हैं: मैं इस तरह के समाधान की कल्पना कर सकता हूं:

void main (void)
{
  int a = 0;

  for (; 1 != a;)
  {
    foo(x, &a);
  } 
}

void foo( int x, int * a)
{
  if (succeeded)
  {
    /* set the break condition*/
    *a = 1;
  }
  else
  {
    *a = 0;
  }
}

यह मेरी पहली पोस्ट है, इसलिए, कृपया मेरी क्षमा करें, अगर मेरा स्वरूपण गड़बड़ हो गया है :)


यह एक और विचार है जो संभव हो सकता है या नहीं भी हो सकता है: चारों ओर एक चर रखें जो foo को नो-ऑप में बदल सकता है:

int broken = 0;

void foo (int a) {
    if (broken) return;

    printf("a: %d", a);
    broken = 1; // "break"
}

int main(void) {
    for (int i = 0; i <= 100; i++) {
        foo(i);
    }
    return 0;
}

यह घड़ी चक्रों के कुछ नुकसान को छोड़कर कार्यात्मक रूप से वही है (फ़ंक्शन को कॉल किया जाएगा, लेकिन केवल कथन कथन करें), और लूप को बदलने की कोई आवश्यकता नहीं है। यह थ्रेडसेफ नहीं है और केवल पहली बार काम करता है (लेकिन यदि आवश्यक हो तो 0 के बराबर के साथ बुलाए जाने पर foo broken वैरिएबल 0 को रीसेट कर सकता है)।

तो बहुत अच्छा नहीं, लेकिन एक विचार जिसका अभी तक उल्लेख नहीं किया गया था।


break , जैसे goto , केवल उसी फ़ंक्शन के भीतर स्थानीय रूप से कूद सकते हैं, लेकिन यदि आपको बिल्कुल करना है, तो आप longjmp और longjmp उपयोग कर सकते हैं:

#include <stdio.h>
#include <setjmp.h>

jmp_buf jump_target;

void foo(void)
{
    printf("Inside foo!\n");
    longjmp(jump_target, 1);
    printf("Still inside foo!\n");
}

int main(void) {
    if (setjmp(jump_target) == 0)
        foo();
    else
        printf("Jumped out!\n");
    return 0;
}

longjmp लिए कॉल longjmp कॉल पर वापस कूद जाएगा। setjmp से वापसी मूल्य दिखाता है कि क्या यह कूद लक्ष्य निर्धारित करने के बाद लौट रहा है, या यदि यह कूद से लौट रहा है।

आउटपुट:

Inside foo!
Jumped out!

सही ढंग से उपयोग किए जाने पर नॉनोकोकल कूद सुरक्षित होते हैं, लेकिन ध्यान से सोचने के लिए कई चीजें हैं:

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

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


break कथन है जो संकलन समय के दौरान हल किया जाता है। इसलिए संकलक को उसी फ़ंक्शन के भीतर / लूप के लिए उपयुक्त खोजना चाहिए। ध्यान दें कि इस बात की कोई गारंटी नहीं है कि समारोह कहीं और से नहीं बुलाया जा सकता है।





break