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




for-loop break (12)

इस प्रश्न का उत्तर पहले ही दिया जा चुका है, लेकिन मुझे लगता है कि सी ++ में लूप से बाहर निकलने के लिए सभी संभावित विकल्पों में डेल करना उचित है। मूल रूप से पांच संभावनाएं हैं:

  • एक लूप स्थिति का उपयोग करना
  • एक break हालत का उपयोग करना
  • return स्थिति का उपयोग करना
  • अपवादों का उपयोग करना
  • goto का उपयोग करना

निम्नलिखित में, मैं c ++ 14 का उपयोग करके इन विकल्पों के लिए उपयोग मामलों का वर्णन करूंगा। हालांकि, आप इन सभी को सी ++ के पूर्व संस्करणों में (शायद अपवादों को छोड़कर) कर सकते हैं। इसे छोटा रखने के लिए, मैं शामिल और मुख्य कार्य को छोड़ दूंगा। कृपया टिप्पणी करें, अगर आपको लगता है कि कुछ हिस्से को और स्पष्टता की आवश्यकता है।

1. एक लूप स्थिति का उपयोग करना

लूप से बाहर निकलने का मानक तरीका एक लूप स्थिति है। लूप स्थिति किसी कथन के मध्य भाग में, या while कथन के बीच में लिखा गया है:

for(something; LOOP CONDITION; something) {
    ... 
}
while (LOOP CONDITION)
    ... 
}
do {
    ... 
} while (LOOP CONDITION);

लूप स्थिति तय करती है कि क्या लूप दर्ज किया जाना चाहिए, और यदि लूप दोहराया जाना चाहिए। उपरोक्त सभी मामलों में, लूप को दोहराने के लिए स्थिति को true होना चाहिए।

उदाहरण के तौर पर, यदि हम संख्या 0 से 2 तक आउटपुट करना चाहते हैं, तो हम लूप और लूप स्थिति का उपयोग कर कोड लिख सकते हैं:

for (auto i = 0; i <= 2; ++i)
    std::cout << i << '\n';
std::cout << "done";

यहां स्थिति i <= 2 । जब तक यह स्थिति true , तब तक लूप चल रहा रहता है।

एक वैकल्पिक कार्यान्वयन स्थिति को एक चर में बदलना होगा:

auto condition = false;

for (auto i = 0; !condition; ++i) {
    std::cout << i << '\n';
    condition = i > 2;
}
std::cout << "done";

दोनों संस्करणों के लिए आउटपुट की जांच, हमें वांछित परिणाम मिलते हैं:

0
1
2
done

वास्तविक दुनिया एप्लिकेशन में आप लूप स्थिति का उपयोग कैसे करेंगे?

सी ++ परियोजनाओं के अंदर दोनों संस्करणों का व्यापक रूप से उपयोग किया जाता है। यह ध्यान रखना महत्वपूर्ण है कि पहला संस्करण अधिक कॉम्पैक्ट है और इसलिए समझना आसान है। लेकिन दूसरा संस्करण आमतौर पर प्रयोग किया जाता है यदि स्थिति अधिक जटिल है या मूल्यांकन के लिए कई चरणों की आवश्यकता है।

उदाहरण के लिए:

auto condition = false;
for (auto i = 0; !condition; ++i)
    if (is_prime(i))
        if (is_large_enough(i)) {
            key = calculate_cryptographic_key(i, data);
            if (is_good_cryptographic_key(key))
                condition = true;
        }

2. एक break हालत का उपयोग करना

लूप से बाहर निकलने का एक और आसान तरीका break कीवर्ड का उपयोग करना है। यदि इसका उपयोग लूप के अंदर किया जाता है, तो निष्पादन बंद हो जाएगा, और लूप बॉडी के बाद जारी रहेगा:

for (auto i = 0; true; ++i) {
    if (i == 3)
        break;
    std::cout << i << '\n';
}
std::cout << "done";

यह वर्तमान संख्या को आउटपुट करेगा, और इसे तब तक i जब तक कि i 3 के मान तक नहीं पहुंच जाता। यहां if स्टेटमेंट हमारी break स्थिति है। यदि स्थिति true , तो लूप टूट गया है (नोट करें ! ) और निष्पादन अगली पंक्ति के साथ जारी है, प्रिंटिंग done

परीक्षण करना, हमें वास्तव में अपेक्षित परिणाम मिलते हैं:

0
1
2
done

यह महत्वपूर्ण है कि यह केवल कोड में सबसे ऊपर लूप को रोक देगा। इसलिए, यदि आप एकाधिक लूप का उपयोग करते हैं, तो यह अवांछित व्यवहार का कारण बन सकता है:

for (auto j = 0; true; ++j)
    for (auto i = 0; true; ++i) {
        if (i == 3)
            break;
        std::cout << i << '\n';
    }
std::cout << "done";

इस कोड के साथ हम ऊपर दिए गए उदाहरण के समान परिणाम प्राप्त करना चाहते थे, लेकिन इसके बजाय हमें एक अनंत लूप मिलता है, क्योंकि break केवल i ऊपर लूप को रोकता है, और j पर एक नहीं!

परीक्षण कर रहा है:

0
1
2
0
1
2
...

असली दुनिया एप्लिकेशन में break हालत का उपयोग कैसे करेंगे?

आमतौर पर break का उपयोग केवल आंतरिक लूप के हिस्सों को छोड़ने के लिए किया जाता है, या अतिरिक्त लूप निकास जोड़ने के लिए किया जाता है।

उदाहरण के लिए, प्राइम नंबरों के लिए फ़ंक्शन परीक्षण में, आप इसे निष्पादन के बाकी हिस्सों को छोड़ने के लिए उपयोग करेंगे, जैसे ही आपको कोई ऐसा मामला मिलेगा जहां वर्तमान संख्या प्रमुख नहीं है:

auto is_prime = true;
for (auto i = 0; i < p; ++i) {
    if (p%i == 0) { //p is dividable by i!
        is_prime = false;
        break; //we already know that p is not prime, therefore we do not need to test more cases!
    }

या, यदि आप तारों के वेक्टर खोज रहे हैं, तो आप आम तौर पर लूप हेड में डेटा का अधिकतम आकार डालते हैं, और यदि आपको वास्तव में वह डेटा मिल जाता है जिसे आप खोज रहे हैं तो लूप से बाहर निकलने के लिए अतिरिक्त स्थिति का उपयोग करें।

auto j = size_t(0);
for (auto i = size_t(0); i < data.size(); ++i)
    if (data[i] == "Hello") { //we found "Hello"!
        j = i;
        break; //we already found the string, no need to search any further!
    }

3. return स्थिति का उपयोग करना

return कीवर्ड वर्तमान दायरे से बाहर निकलता है और कॉलिंग फ़ंक्शन पर वापस आता है। इस प्रकार इसका उपयोग लूप से बाहर निकलने के लिए किया जा सकता है, और इसके अतिरिक्त, कॉलर को एक नंबर वापस दें। एक लूप (और इसके फ़ंक्शन) से बाहर निकलने के लिए return का उपयोग करना और परिणाम लौटना एक आम मामला है।

उदाहरण के लिए, हम ऊपर से is_prime फ़ंक्शन को फिर से लिख सकते हैं:

auto inline is_prime(int p) {
    for (auto i = 0; i < p; ++i)
        if (p%i == 0) //p is dividable by i!
            return false; //we already know that p is not prime, and can skip the rest of the cases and return the result
    return true; //we didn't find any divisor before, thus p must be prime!
}

एकाधिक लूप से बाहर निकलने के लिए return कीवर्ड का भी उपयोग किया जा सकता है:

auto inline data_has_match(std::vector<std::string> a, std::vector<std::string> b) {
    for (auto i = size_t(0); i < a.size(); ++i)
        for (auto j = size_t(0); j < a.size(); ++j)
            if (a[i] == b[j])
                return true; //we found a match! nothing to do here
    return false; //no match was found
}

वास्तविक दुनिया एप्लिकेशन में return स्थिति का उपयोग कैसे करेंगे?

छोटे कार्यों के अंदर, return अक्सर लूप से बाहर निकलने के लिए उपयोग किया जाता है और सीधे परिणाम लौटाता है। इसके अलावा, बड़े कार्यों के अंदर, return कोड को स्पष्ट और पठनीय रखने में मदद करता है:

for (auto i = 0; i < data.size(); ++i) {
    //do some calculations on the data using only i and put them inside result
    if (is_match(result,test))
        return result;
    for (auto j = 0; j < i; ++j) {
        //do some calculations on the data using i and j and put them inside result
        if (is_match(result,test))
            return result;
    }
}
return 0; //we need to return something in the case that no match was found

जो समझने के लिए बहुत आसान है, से:

auto break_i_loop = false;
auto return_value = 0;
for (auto i = 0; !break_i_loop; ++i) {
    //do some calculations on the data using only i and put them inside result
    if (is_match(result,test)) { //a match was found, save the result and break the loop!
        return_value = result;
        break;
    }
    for (auto j = 0; j < i; ++j) {
        //do some calculations on the data using i and j and put them inside result
        if (is_match(result,test)) { //a match was found, save the result, break the loop, and make sure that we break the outer loop too!
            return_value = result;
            break_i_loop = true;
            break;
        }
    }
    if (!break_i_loop) //if we didn't find a match, but reached the end of the data, we need to break the outer loop
        break_i_loop = i >= data.size();
}
return return_value; //return the result

4. अपवादों का उपयोग करना

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

वास्तविक दुनिया एप्लिकेशन में आप अपवाद का उपयोग कैसे करेंगे?

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

auto inline inverse_data(std::vector<int>& data) {
    for (auto i = size_t(0); i < data.size(); ++i)
        if (data[i] == 0)
            throw std::string("Division by zero on element ") + std::to_string(i) + "!";
        else
            data[i] = 1 / data[i];
}

हम कॉलिंग फ़ंक्शन के अंदर इस अपवाद को संभाल सकते हैं:

while (true)
    try {
        auto data = get_user_input();
        inverse = inverse_data(data);
        break;
    }
    catch (...) {
        std::cout << "Please do not put zeros into the data!";
    }

यदि data में शून्य है, तो inverse_data एक अपवाद फेंक देगा, break कभी निष्पादित नहीं होता है, और उपयोगकर्ता को फिर से डेटा इनपुट करना होता है।

अतिरिक्त त्रुटि प्रकारों के साथ, इस तरह के त्रुटि प्रबंधन के लिए और भी अग्रिम विकल्प हैं ..., लेकिन यह एक और दिन के लिए एक विषय है।

** आपको कभी क्या नहीं करना चाहिए! **

जैसा कि पहले उल्लेख किया गया है, अपवाद एक महत्वपूर्ण रनटाइम ओवरहेड उत्पन्न कर सकते हैं। इसलिए, उन्हें केवल असाधारण मामलों में ही इस्तेमाल किया जाना चाहिए। हालांकि निम्नलिखित कार्य लिखना संभव है, कृपया नहीं!

auto inline next_prime(int start) {
    auto p = start;
    try {
        for (auto i = start; true; ++i)
            if (is_prime(i)) {
                p = i;
                throw;
            }
   }
   catch (...) {}
   return p;
 }

5. goto का उपयोग करना

goto कीवर्ड को अधिकांश प्रोग्रामर द्वारा नफरत है, क्योंकि यह कोड को पढ़ने के लिए कठिन बनाता है, और इसमें अनपेक्षित साइड इफेक्ट्स हो सकते हैं। हालांकि, इसका उपयोग बाहर निकलने के लिए किया जा सकता है (एकाधिक) लूप:

for (auto j = 0; true; ++j)
    for (auto i = 0; true; ++i) {
        if (i == 3)
            goto endloop;
        std::cout << i << '\n';
    }
endloop:
std::cout << "done";

यह लूप समाप्त हो जाएगा (भाग 2 में लूप की तरह नहीं), और आउटपुट:

0
1
2
done

असली दुनिया एप्लिकेशन में आप goto उपयोग कैसे करेंगे?

99.9% मामलों में goto कीवर्ड का उपयोग करने की कोई आवश्यकता नहीं है। एकमात्र अपवाद एम्बेडेड सिस्टम हैं, जैसे आर्डिनो, या बहुत उच्च प्रदर्शन कोड। यदि आप इन दोनों में से किसी एक के साथ काम कर रहे हैं, तो आप तेजी से या अधिक कुशल कोड बनाने के लिए goto का उपयोग करना चाहेंगे। हालांकि, रोजमर्रा के प्रोग्रामर के लिए, डाउनसाइड्स goto का उपयोग करने के लाभ से कहीं अधिक बड़े होते हैं।

यहां तक ​​कि यदि आपको लगता है कि आपका केस 0.1% में से एक है, तो आपको यह जांचना होगा कि goto वास्तव में आपके निष्पादन में सुधार करता है या नहीं। अक्सर, break या return हालत का उपयोग करने से अधिक तेज़ होता है, क्योंकि कंपाइलर में goto युक्त कोड को समझने में कठिन समय होता है।

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

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() में ब्रेक लूप के भीतर नहीं है)

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

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

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


लूप के for मैन्युअल रूप से अपने फ़ंक्शन को रेखांकित करने पर विचार करें। यदि यह फ़ंक्शन एकाधिक लूप में कहा जाता है, तो इसे मैक्रो के रूप में परिभाषित करें:

#define f()\
printf("a: %d", a);\
break;

आप लूप के अंदर अपने फ़ंक्शन में एक त्रुटि फेंक सकते हैं और लूप के बाहर उस त्रुटि को पकड़ सकते हैं।

#include <stdio.h>

void foo (int a) {
    printf("a: %d", a);
    if (a == 50)
    {
       throw a;
    }
}

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

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

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


इस तरह के मामले में लूप के बजाए && के साथ कई सशर्त बयानों के साथ थोड़ी देर () लूप का उपयोग करने पर विचार करें। यद्यपि आप 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 इत्यादि के उपयोग के खिलाफ स्पष्ट रूप से नहीं हूं। लेकिन मुझे लगता है कि इस मामले में इन उपायों का उपयोग किए बिना एक बहुत ही सरल और अधिक संक्षिप्त समाधान उपलब्ध है!


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

सी संकलित होने के तरीके के कारण यह पता होना चाहिए कि समारोह कहां से तोड़ना है। चूंकि आप इसे कहीं से भी कॉल कर सकते हैं, या यहां तक ​​कि कहीं भी ब्रेक का कोई मतलब नहीं है, तो आप 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);


यदि आप break निर्देश का उपयोग नहीं कर सकते हैं तो आप अपने मॉड्यूल में एक स्थानीय चर परिभाषित कर सकते हैं और लूप के for दूसरी रन स्थिति जोड़ सकते हैं। उदाहरण के लिए निम्न कोड की तरह:

#include <stdio.h>
#include <stdbool.h>

static bool continueLoop = true;

void foo (int a)
{
    bool doBreak = true;

    printf("a: %d",a);

    if(doBreak == true){
        continueLoop = false;
    }
    else {
        continueLoop = true;
    }
}
int main(void) {
    continueLoop = true;   // Has to be true before entering the loop
    for (int i = 0; (i <= 100) && continueLoop; i++)
    {
        foo(i);
    }
    return 0;
}

ध्यान दें कि इस उदाहरण में यह वास्तव में एक break इंस्ट्रक्शन नहीं है, लेकिन लूप के लिए एक और पुनरावृत्ति नहीं होगी। यदि आप break करना चाहते हैं तो आपको वैरिएबल continueLoop साथ एक if -condition डालना होगा, जो break ओर जाता है:

int main(void) {
    continueLoop = true;   // Has to be true before entering the loop
    for (int i = 0; i <= 100; i++)
    {
        foo(i);
        if(!continueLoop){
            break;
        }
    }
    return 0;
}

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

#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;
   }
}

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


मेरा मानना ​​है कि यह संबंधित है कि 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.

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

#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