সি-তে ত্রুটি পরিচালনার জন্য গোটোর বৈধ ব্যবহার?


95

এই প্রশ্নটি আসলে কিছুক্ষণ আগে প্রোগ্রামিং.আরডিট.কম এ একটি আকর্ষণীয় আলোচনার ফলাফল । এটি মূলত নিম্নলিখিত কোডে ফোটে:

int foo(int bar)
{
    int return_value = 0;
    if (!do_something( bar )) {
        goto error_1;
    }
    if (!init_stuff( bar )) {
        goto error_2;
    }
    if (!prepare_stuff( bar )) {
        goto error_3;
    }
    return_value = do_the_thing( bar );
error_3:
    cleanup_3();
error_2:
    cleanup_2();
error_1:
    cleanup_1();
    return return_value;
}

এখানকার ব্যবহার gotoসবচেয়ে ভাল উপায় বলে মনে হচ্ছে, এর ফলে সমস্ত সম্ভাবনার সবচেয়ে পরিষ্কার এবং সবচেয়ে কার্যকর কোড তৈরি হয়েছে বা কমপক্ষে তাই এটি আমার কাছে মনে হয়। কোড সম্পূর্ণ স্টিভ ম্যাককনেল এর উদ্ধৃতি :

গোটো এমন একটি রুটিনে কার্যকর যেগুলি সংস্থানগুলি বরাদ্দ করে, সেই সংস্থানগুলিতে অপারেশন সম্পাদন করে এবং পরে সংস্থানগুলি হ্রাস করে। গোটো দিয়ে আপনি কোডের একটি বিভাগে পরিষ্কার করতে পারেন। Goo আপনার ত্রুটি সনাক্ত করে এমন প্রতিটি স্থানে সংস্থানগুলি হ্রাস করতে আপনার ভুলে যাওয়ার সম্ভাবনা হ্রাস করে।

এই বিভাগের জন্য এই পদ্ধতির জন্য অন্য একটি সমর্থন লিনাক্স ডিভাইস ড্রাইভার ড্রাইভার বই থেকে এসেছে ।

আপনি কি মনে করেন? এই ক্ষেত্রে gotoসি এর জন্য বৈধ ব্যবহার ? আপনি কি অন্যান্য পদ্ধতিগুলি পছন্দ করেন, যা আরও সংশ্লেষিত এবং / অথবা কম দক্ষ কোড তৈরি করে, তবে এড়াতে চান goto?



@ এলি: আপনি ট্যাগগুলি সরিয়ে ফাংশনটি (ক্লিনআপ_3 ();) যদি রাখেন না কেন?

@ আকিতো: আপনার মানে কী? আপনি একটি সম্পূর্ণ কোড নমুনা সহ উত্তর হিসাবে আপনার পরামর্শ পোস্ট করতে পারেন?
এলি বেন্ডারস্কি

@ এলিবেেন্ডারস্কি: দয়া করে আমার উত্তরটি দেখুন।

ভিজ্যুয়াল বেসিক (ভিবিএস এবং ভিবি 6 অন্তর্ভুক্ত) থেকে আমি যে জিনিসগুলিকে সবচেয়ে বেশি ঘৃণা করি তা হ'ল on error goto errorত্রুটি পরিচালনা ব্যবস্থা: :)
Manu343726

উত্তর:


64

এফডাব্লুআইআইএফ, আমি প্রশ্নের উত্তরটিতে এখন পর্যন্ত উত্তরগুলিতে দেওয়া বিকল্পগুলির চেয়ে আরও বেশি পঠনযোগ্য এবং সহজেই বোঝার জন্য যে আইডিয়মটি দিয়েছেন তাতে ত্রুটিটি আমি খুঁজে পেয়েছি। যদিও gotoসাধারণভাবে একটি খারাপ ধারণা, এটি সাধারণ এবং অভিন্ন পদ্ধতিতে করা হলে ত্রুটি পরিচালনার জন্য কার্যকর হতে পারে। এই পরিস্থিতিতে যদিও এটি একটি goto, এটি সুসংজ্ঞায়িত এবং আরও বা কম কাঠামোগত পদ্ধতিতে ব্যবহৃত হচ্ছে।


4
তিনি কি কেবল এই ট্যাগগুলি সরিয়ে ফাংশনগুলি সরাসরি putোকাতে পারবেন না? এটি কি আরও পাঠযোগ্য হবে না?

8
@ স্টার্টআপক্রজি, আমি জানি এটি বহু বছরের পুরনো, তবে এই সাইটে পোস্টগুলির বৈধতার স্বার্থে আমি উল্লেখ করবো যে তিনি পারবেন না। যদি তার কোডটিতে গোটো ত্রুটি 3 এ ত্রুটি পান তবে তিনি 1 2 এবং 3 সাফাই চালাবেন, আপনার উত্সাহিত সমাধানে তিনি কেবল ক্লিনআপ চালাতেন 3.. তিনি বাসা বাঁধতে পারেন, তবে এটি কেবল তীরের অ্যান্টিপ্যাটার্ন হবে, প্রোগ্রামাররা এড়ানো উচিত ।
gbtimmon

18

একটি সাধারণ নিয়ম হিসাবে, গোটো এড়ানো এড়ানো একটি ভাল ধারণা, তবে ডিজকস্ট্রা প্রথম 'গোটো বিবেচিত ক্ষতিকারক' লেখার সময় যে অপব্যবহারগুলি প্রচলিত ছিল তা আজকাল বেশিরভাগ মানুষের মনকে বিকল্প হিসাবে চিহ্নিতও করে না।

আপনার রূপরেখাটি যা ত্রুটি পরিচালনা করা সমস্যার সাধারণ সমাধানযোগ্য - এটি যতক্ষণ না সতর্কতার সাথে ব্যবহার করা হয় ততক্ষণ আমার পক্ষে এটি ঠিক।

আপনার নির্দিষ্ট উদাহরণটি নিম্নরূপে সরল করা যেতে পারে (পদক্ষেপ 1):

int foo(int bar)
{
    int return_value = 0;
    if (!do_something(bar)) {
        goto error_1;
    }
    if (!init_stuff(bar)) {
        goto error_2;
    }
    if (prepare_stuff(bar))
    {
        return_value = do_the_thing(bar);
        cleanup_3();
    }
error_2:
    cleanup_2();
error_1:
    cleanup_1();
    return return_value;
}

প্রক্রিয়া চালিয়ে যাওয়া:

int foo(int bar)
{
    int return_value = 0;
    if (do_something(bar))
    {   
        if (init_stuff(bar))
        {
            if (prepare_stuff(bar))
            {
                return_value = do_the_thing(bar);
                cleanup_3();
            }
            cleanup_2();
        }
        cleanup_1();
    }
    return return_value;
}

এটি, আমি বিশ্বাস করি, মূল কোডের সমান। এটি বিশেষত পরিষ্কার দেখাচ্ছে যেহেতু মূল কোডটি নিজেই খুব পরিষ্কার এবং সুসংহত ছিল। প্রায়শই, কোডের টুকরোগুলি তার মতো পরিপাটি হয় না (যদিও আমি তাদের একটি যুক্তি গ্রহণ করব); উদাহরণস্বরূপ, প্রায়শই দেখানো অপেক্ষা ইনিশিয়ালাইজেশন (সেটআপ) রুটিনগুলিতে যাওয়ার জন্য আরও বেশি স্টেট থাকে এবং তাই ক্লিনআপ রুটিনগুলিতেও যাওয়ার জন্য আরও স্টেট থাকে।


24
হ্যাঁ, নেস্টেড সমাধানটি একটি সম্ভাব্য বিকল্প। দুর্ভাগ্যক্রমে নীড়ের স্তর আরও গভীর হওয়ার সাথে সাথে এটি কম কার্যকর হয়।
এলি বেন্ডারস্কি 14

4
@ এলিবেন: সম্মত - তবে গভীর বাসা বাঁধাই (সম্ভবত এটি) একটি ইঙ্গিত হতে পারে যে আপনাকে আরও ফাংশন প্রবর্তন করতে হবে, বা প্রস্তুতিমূলক পদক্ষেপগুলি আরও বেশি করতে হবে, বা অন্যথায় আপনার কোডটি রিফ্যাক্টর করা উচিত। আমি তর্ক করতে পারি যে প্রস্তুতির প্রতিটি কার্যক্রমে তাদের সেটআপ করা উচিত, চেইনে পরেরটিকে কল করা উচিত এবং নিজের ক্লিনআপ করা উচিত। এটি সেই কাজটিকে স্থানীয়করণ করে - আপনি সম্ভবত তিনটি পরিষ্কার করার জন্য সংরক্ষণ করতে পারেন। এটি সেটআপ বা ক্লিনআপ ফাংশনগুলির কোনও অন্য কোনও কলিং সিকোয়েন্সে (ব্যবহারযোগ্য) ব্যবহৃত হয় কিনা তার উপরও আংশিকভাবে নির্ভর করে।
জোনাথন লেফলার

6
দুর্ভাগ্যক্রমে এটি লুপগুলির সাথে কাজ করে না - যদি কোনও লুপের ভিতরে কোনও ত্রুটি দেখা দেয়, তবে পতাকা স্থাপন এবং পরীক্ষার বিকল্প এবং 'ব্রেক' বিবৃতি (যা কেবল চতুরতার সাথে ছদ্মবেশযুক্ত গোটো) এর চেয়ে অনেক বেশি পরিষ্কার a
অ্যাডাম রোজনফিল্ড

4
@ স্মিথ, বুলেট-প্রুফ ন্যস্ত করা ছাড়া গাড়ি চালানোর মতো আরও কিছু।
স্ট্র্যাজার

6
আমি জানি আমি এখানে নেক্রোমেন্সিং করছি, তবে আমি এই পরামর্শটি বরং দুর্বল বলে মনে করি - তীরের অ্যান্টি-প্যাটার্নটি এড়ানো উচিত।
কিংআরডিকাল

16

আমি অবাক হয়েছি কেউ এই বিকল্পটির পরামর্শ দেয়নি, তাই যদিও প্রশ্নটি প্রায় সময় হয়ে গেছে আমি এটিকে যুক্ত করব: এই ইস্যুটির সুরাহা করার একটি ভাল উপায় হ'ল চলমান অবস্থার উপর নজর রাখতে ভেরিয়েবল ব্যবহার করা। এটি এমন একটি প্রযুক্তি যা gotoক্লিনআপ কোডে পৌঁছানোর জন্য ব্যবহৃত হয় কিনা তা ব্যবহার করা যায়। যে কোনও কোডিং কৌশল হিসাবে, এটির পক্ষে মতামত এবং বোধগম্যতা রয়েছে এবং প্রতিটি পরিস্থিতির জন্য উপযুক্ত হবে না তবে আপনি যদি এমন কোনও শৈলী চয়ন করেন তবে এটি বিবেচনা করার মতো especially বিশেষত যদি আপনি gotoগভীরভাবে নেস্টেড ifএস না দিয়ে এড়াতে চান ।

মূল ধারণাটি হ'ল, যে কোনও ক্লিনআপ ক্রিয়াকলাপ গ্রহণের প্রয়োজন হতে পারে তার জন্য একটি ভেরিয়েবল রয়েছে যার মূল্য থেকে আমরা বলতে পারি যে ক্লিনআপটি করা দরকার কি না।

আমি gotoপ্রথমে সংস্করণটি দেখাব , কারণ এটি মূল প্রশ্নের কোডের নিকটে।

int foo(int bar)
{
    int return_value = 0;
    int something_done = 0;
    int stuff_inited = 0;
    int stuff_prepared = 0;


    /*
     * Prepare
     */
    if (do_something(bar)) {
        something_done = 1;
    } else {
        goto cleanup;
    }

    if (init_stuff(bar)) {
        stuff_inited = 1;
    } else {
        goto cleanup;
    }

    if (prepare_stuff(bar)) {
        stufF_prepared = 1;
    } else {
        goto cleanup;
    }

    /*
     * Do the thing
     */
    return_value = do_the_thing(bar);

    /*
     * Clean up
     */
cleanup:
    if (stuff_prepared) {
        unprepare_stuff();
    }

    if (stuff_inited) {
        uninit_stuff();
    }

    if (something_done) {
        undo_something();
    }

    return return_value;
}

অন্যান্য কয়েকটি কৌশলগুলির মধ্যে এটির একটি সুবিধা হ'ল, যদি আরম্ভের ফাংশনগুলির ক্রম পরিবর্তন করা হয় তবে সঠিক পরিচ্ছন্নতাটি ঘটবে - উদাহরণস্বরূপ, switchঅন্য উত্তরে বর্ণিত পদ্ধতিটি ব্যবহার করে , যদি আরম্ভের ক্রম পরিবর্তন হয়, তবেswitch কিছু পরিষ্কার করার চেষ্টা এড়াতে খুব সাবধানে সম্পাদনা করতে হবে আসলে প্রথমদিকে আরম্ভ করা হয়নি।

এখন, কিছু যুক্তিযুক্ত হতে পারে যে এই পদ্ধতিটি অতিরিক্ত পরিমাণে ভেরিয়েবল যুক্ত করে - এবং প্রকৃতপক্ষে এই ক্ষেত্রে এটি সত্য - তবে বাস্তবে সাধারণত একটি বিদ্যমান ভেরিয়েবল ইতিমধ্যে ট্র্যাক করে, বা প্রয়োজনীয় অবস্থার উপর নজর রাখতে পারে। উদাহরণস্বরূপ, যদি prepare_stuff()প্রকৃতপক্ষে কলটি হয় malloc()বা তার কাছে হয় open()তবে ফেরত পয়েন্টার বা ফাইল বিবরণী ধারণকারী চলকটি ব্যবহার করা যেতে পারে - উদাহরণস্বরূপ:

int fd = -1;

....

fd = open(...);
if (fd == -1) {
    goto cleanup;
}

...

cleanup:

if (fd != -1) {
    close(fd);
}

এখন, আমরা অতিরিক্তভাবে একটি ভেরিয়েবলের মাধ্যমে ত্রুটির স্থিতি ট্র্যাক করি, আমরা এড়াতে পারি goto সম্পূর্ণরূপে , এবং এখনও সঠিকভাবে পরিষ্কার করতে পারি না, এমন ইনডেন্টেশন না থাকলে যা আমাদের আরও আরম্ভ করার প্রয়োজন হয়:

int foo(int bar)
{
    int return_value = 0;
    int something_done = 0;
    int stuff_inited = 0;
    int stuff_prepared = 0;
    int oksofar = 1;


    /*
     * Prepare
     */
    if (oksofar) {  /* NB This "if" statement is optional (it always executes) but included for consistency */
        if (do_something(bar)) {
            something_done = 1;
        } else {
            oksofar = 0;
        }
    }

    if (oksofar) {
        if (init_stuff(bar)) {
            stuff_inited = 1;
        } else {
            oksofar = 0;
        }
    }

    if (oksofar) {
        if (prepare_stuff(bar)) {
            stuff_prepared = 1;
        } else {
            oksofar = 0;
        }
    }

    /*
     * Do the thing
     */
    if (oksofar) {
        return_value = do_the_thing(bar);
    }

    /*
     * Clean up
     */
    if (stuff_prepared) {
        unprepare_stuff();
    }

    if (stuff_inited) {
        uninit_stuff();
    }

    if (something_done) {
        undo_something();
    }

    return return_value;
}

আবার এর সম্ভাব্য সমালোচনা রয়েছে:

  • সমস্ত "যদি" এর অভিনয় ক্ষতিগ্রস্ত করবেন না? না - কারণ সাফল্যের ক্ষেত্রে, আপনাকে যে কোনও উপায়ে সমস্ত চেক করতে হবে (অন্যথায় আপনি সমস্ত ত্রুটির ক্ষেত্রে পরীক্ষা করছেন না); এবং ব্যর্থতার ক্ষেত্রে বেশিরভাগ সংকলক ব্যর্থতার ক্রমটি অনুকূল করে তোলেif (oksofar) ক্লিনআপ কোডে (জিসিসি অবশ্যই করে) কোনও একক লাফের জন্য চেকগুলির তোলে - এবং কোনও ক্ষেত্রে ত্রুটি কেস কার্য সম্পাদনের জন্য সাধারণত কম সমালোচিত হয়।
  • এটি কি আরও একটি পরিবর্তনশীল যুক্ত করছে না? এই ক্ষেত্রে হ্যাঁ, তবে প্রায়শই return_valueভেরিয়েবলটি oksofarএখানে যে ভূমিকা পালন করে তা ব্যবহার করতে পারেন । যদি আপনি ধারাবাহিক উপায়ে ত্রুটিগুলি ফিরিয়ে আনতে আপনার ফাংশনগুলি গঠন করেন তবে আপনি ifপ্রতিটি ক্ষেত্রে দ্বিতীয়টি এড়াতে পারেন :

    int return_value = 0;
    
    if (!return_value) {
        return_value = do_something(bar);
    }
    
    if (!return_value) {
        return_value = init_stuff(bar);
    }
    
    if (!return_value) {
        return_value = prepare_stuff(bar);
    }
    

    এর মতো কোডিংয়ের একটি সুবিধা হ'ল ধারাবাহিকতাটির অর্থ হ'ল যে কোনও জায়গাতেই মূল প্রোগ্রামার রিটার্নের মানটি ঘাড়ে থাম্বের মতো চেক করতে ভুলে গিয়েছে, যাতে বাগগুলি খুঁজে পাওয়া খুব সহজ হয়ে যায় (যে এক শ্রেণির) বাগগুলি।

সুতরাং - এটি (এখনও) আরও একটি স্টাইল যা এই সমস্যাটি সমাধান করতে ব্যবহার করা যেতে পারে। সঠিকভাবে ব্যবহৃত হয়েছে এটি খুব পরিষ্কার, সামঞ্জস্যপূর্ণ কোডের অনুমতি দেয় - এবং কোনও কৌশল হিসাবে, ভুল হাতে এটি দীর্ঘায়িত এবং বিভ্রান্তিকর কোড উত্পাদন করতে শেষ করতে পারে :-)


4
দেখে মনে হচ্ছে আপনি পার্টিতে দেরি করেছেন তবে উত্তরটা অবশ্যই আমার পছন্দ হয়েছে!

লিনাস সম্ভবত আপনার কোডগুলি ব্লগগুলিকে
ফিজ

4
@ ইউজার 3588161: যদি তিনি থাকেন তবে এটি তাঁর পূর্বানুমতিপূর্ণ - তবে আপনি যে নিবন্ধটির সাথে লিঙ্ক করেছেন তার উপর ভিত্তি করে আমি নিশ্চিত নই, সেটাই ঘটনা: লক্ষ্য করুন যে শৈলীতে আমি বর্ণনা করছি, (1) শর্তাবলী বাসা বাঁধে না নির্বিচারে গভীরভাবে এবং (২) যাইহোক আপনার প্রয়োজনের তুলনায় কোনও অতিরিক্ত "যদি" বিবৃতি নেই (ধরে নিবেন যে আপনি সমস্ত রিটার্ন কোড পরীক্ষা করে যাচ্ছেন)।
শ্রদ্ধেয়

এতোটাই এর পরিবর্তে ভয়াবহ গোটো এবং আরও খারাপ তীর-বিরোধী সমাধানের পরিবর্তে!
প্যারাম্যাগনেটিক ক্রোস্যান্ট

8

মূলশব্দটির সমস্যাটি gotoবেশিরভাগ ক্ষেত্রেই ভুল বোঝাবুঝি। এটা সরল-মন্দ নয়। প্রতিটি গোটো দিয়ে আপনি যে অতিরিক্ত কন্ট্রোল পাথ তৈরি করেছেন সে সম্পর্কে আপনাকে সচেতন হওয়া দরকার। আপনার কোড এবং তাই এর বৈধতা সম্পর্কে तर्क করা কঠিন হয়ে পড়ে।

এফডব্লিউআইডাব্লু, আপনি যদি ডেভেলপার.এপল.কম.র টিউটোরিয়ালগুলি সন্ধান করেন তবে তারা ত্রুটি পরিচালনার ক্ষেত্রে গোটো পন্থা নেয়।

আমরা গোটোস ব্যবহার করি না। রিটার্নের মানগুলির উপর একটি উচ্চতর গুরুত্ব দেওয়া হয়। ব্যতিক্রম হ্যান্ডলিংয়ের মাধ্যমে সম্পন্ন হয় setjmp/longjmp- আপনি যা সামান্য পারেন।


8
যদিও আমি অবশ্যই কিছু ক্ষেত্রে সেটজ্যাম্প / লংজ্যাম্প ব্যবহার করেছি যেখানে এটির জন্য আহ্বান করা হয়েছিল, আমি এটিকে গোটোর চেয়েও "খারাপ" বলে বিবেচনা করব (যা আমিও চাইলে কিছুটা কম সংরক্ষিতভাবে ব্যবহার করি) when আমি কেবলমাত্র একবার সেটজ্যাম্প / লংজ্যাম্প ব্যবহার করি যখন হয় (1) লক্ষ্যটি এমনভাবে সমস্ত কিছু বন্ধ করে দিচ্ছে যা তার বর্তমান অবস্থার দ্বারা প্রভাবিত হবে না, বা (২) লক্ষ্যটি নিয়ন্ত্রণ করা সমস্ত কিছুকে পুনরায় নতুন করে আনতে চলেছে সেটজেম্প / লংজ্যাম্প-রক্ষিত ব্লকটি এমন একটি উপায়ে যা বর্তমান অবস্থা থেকে স্বতন্ত্র।
সুপারক্যাট

4

(অকার্যকর) * পয়েন্টারগুলির সাথে নৈতিকভাবে কিছু ভুল হওয়ার চেয়ে গোটো স্টেটমেন্ট সম্পর্কে নৈতিকভাবে কোনও ভুল নেই।

আপনি কীভাবে সরঞ্জামটি ব্যবহার করেন এটি সবই। আপনি উপস্থাপিত (তুচ্ছ) ক্ষেত্রে, একটি কেস স্টেটমেন্ট একই যুক্তি অর্জন করতে পারে, তবে বেশি ওভারহেড থাকা সত্ত্বেও। আসল প্রশ্নটি হচ্ছে, "আমার গতির প্রয়োজনীয়তা কী?"

গোটো ঠিক প্লেইন দ্রুত, বিশেষত যদি আপনি এটি নিশ্চিত করে থাকেন যে এটি একটি সংক্ষিপ্ত লাফের জন্য সংকলন করে। অ্যাপ্লিকেশনগুলির জন্য উপযুক্ত যেখানে গতি একটি প্রিমিয়াম। অন্যান্য অ্যাপ্লিকেশনগুলির জন্য, রক্ষণাবেক্ষণের জন্য / অন্য + ক্ষেত্রে যদি ওভারহেড হিট করা সম্ভবত বোধগম্য হয়।

মনে রাখবেন: Goo অ্যাপ্লিকেশনগুলিকে হত্যা করে না, বিকাশকারীরা অ্যাপ্লিকেশনগুলিকে হত্যা করে।

আপডেট: কেস উদাহরণ এখানে

int foo(int bar) { 
     int return_value = 0 ; 
     int failure_value = 0 ;

     if (!do_something(bar)) { 
          failure_value = 1; 
      } else if (!init_stuff(bar)) { 
          failure_value = 2; 
      } else if (prepare_stuff(bar)) { 
          return_value = do_the_thing(bar); 
          cleanup_3(); 
      } 

      switch (failure_value) { 
          case 2: cleanup_2(); 
          case 1: cleanup_1(); 
          default: break ; 
      } 
} 

4
আপনি কি 'কেস' বিকল্প উপস্থাপন করতে পারেন? এছাড়াও, আমি যুক্তি দিয়ে বলব যে এটি শূন্য * এর থেকে আলাদা, যা সি এর যে কোনও গুরুতর ডেটা স্ট্রাকচার বিমূর্তনের জন্য প্রয়োজনীয়, আমি মনে করি না যে কোনও ব্যক্তি গুরুতরভাবে শূন্য * এর বিরোধিতা করছে, এবং আপনি একটিও বড় কোড বেস পাবেন না without এটা।
এলি বেন্ডারস্কি

পুনরায়: অকার্যকর *, এটি আমার বক্তব্য, নৈতিকভাবে কোনওরকমই ভুল নেই। নীচে স্যুইচ / কেস উদাহরণ। int foo (int বার) return int রিটার্ন_ভ্যালু = 0; int ব্যর্থতা_মূল্য = 0; যদি (! do_someoming (বার)) {ব্যর্থতা_মূল্য = 1; } অন্যথায় যদি (! init_stuff (বার)) {ব্যর্থতা_মূল্য = 2; } অন্যথায় যদি (প্রস্তুতি_ স্টাফ (বার)) {{রিটার্ন_ভ্যালু = কর_ কী_ (বার); ক্লিনআপ 14 (); } স্যুইচ (ব্যর্থতা_মূল্য) {কেস 2: ক্লিনআপ_2 (); বিরতি; কেস 1: ক্লিনআপ_1 (); বিরতি; ডিফল্ট: বিরতি; }}
ওয়েবমার্ক

4
@ ওয়েবমার্ক, দুঃখিত তবে এটি ভয়াবহ! আপনি লেবেলের সাথে পুরোপুরি সিমুলেটেড গেটো করেছেন - লেবেলগুলির জন্য আপনার নিজস্ব অ-বর্ণনামূলক মান আবিষ্কার করে এবং সুইচ / কেস সহ গোটো প্রয়োগ করে implementing ব্যর্থতা_মূল্য = 1 "গোটো ক্লিনআপ_সামথিং" এর চেয়ে পরিষ্কার?
এলি বেন্ডারস্কি

4
আমার মনে হচ্ছে আপনি আমাকে এখানে সেট আপ করেছেন ... আপনার প্রশ্নটি একটি মতামতের জন্য, এবং আমি কী পছন্দ করব। তবুও যখন আমি আমার উত্তরটি অফার করলাম, এটি ভয়াবহ। :-( লেবেলের নামগুলি সম্পর্কে আপনার অভিযোগ হিসাবে, সেগুলি আপনার উদাহরণের মতোই বর্ণনামূলক: ক্লিনআপ_1, ফু, বার
question

4
আমার "সেট আপ" করার এবং কোনও ধরণের নেতিবাচক অনুভূতির কারণ হওয়ার কোনও ইচ্ছা ছিল না, এর জন্য দুঃখিত! এটি কেবল অনুভব করে যে আপনার নতুন পদ্ধতিটি কোনও আরও স্পষ্টতা যোগ না করেই কেবল 'গোটো অপসারণ' এ লক্ষ্যযুক্ত। এটি মনে হয় আপনি গোটো যা করেন তা পুনরায় প্রয়োগ করেছেন, আরও বেশি কোড ব্যবহার করছেন যা কম স্পষ্ট। এই আইএমএইচও করা ভাল জিনিস নয় - কেবলমাত্র এটির জন্য গোটো থেকে মুক্তি পাওয়া।
এলি বেন্ডারস্কি

2

গোটো দরকারী। এটি এমন কিছু যা আপনার প্রসেসরটি করতে পারে এবং এ কারণেই আপনার এতে অ্যাক্সেস থাকা উচিত।

কখনও কখনও আপনি আপনার ফাংশনটিতে কিছুটা যুক্ত করতে চান এবং একক গোটো যাক আপনি এটি সহজেই করেন। এটি সময় বাঁচাতে পারে ..


4
আপনার প্রসেসর করতে পারে এমন প্রতিটি জিনিসে আপনার অ্যাক্সেসের দরকার নেই। বেশিরভাগ সময় গোটো বিকল্পের চেয়ে বিভ্রান্তিকর।
ডেভিড থর্নলি

@DavidThornley: হ্যাঁ, আপনি কি , প্রতি একক জিনিস আপনার প্রসেসর কি করতে পারেন প্রয়োজন এক্সেস অন্যথায়, আপনি আপনার প্রসেসরের নষ্ট করছে। প্রোগ্রামিংয়ের সেরা নির্দেশনা গোটো।
রন মাইমন

1

সাধারণভাবে, আমি এই বিষয়টিকে বিবেচনা করব যে কোডের একটি অংশটি gotoএকটি লক্ষণ হিসাবে ব্যবহার করে সর্বাধিক স্পষ্টভাবে লেখা যেতে পারে যা সাধারণত প্রোগ্রামের প্রবাহটি সাধারণত কাঙ্ক্ষিত থেকে বেশি জটিল is অন্যান্য প্রোগ্রামের কাঠামোগুলিকে অযৌক্তিক উপায়ে gotoএকত্রিত করা রোগের চেয়ে লক্ষণটির চিকিত্সার চেষ্টা করবে। আপনার নির্দিষ্ট উদাহরণ ব্যতীত প্রয়োগ করা অত্যধিক কঠিন হতে পারে goto:

  কর {
    .. জিনিস 1 সেট আপ করুন যা কেবল প্রারম্ভিক প্রস্থানের ক্ষেত্রে ক্লিনআপ প্রয়োজন need
    যদি (ত্রুটি) বিরতি;
    কর
    {
      .. জিনিস 2 সেট আপ করুন যা প্রারম্ভিক প্রস্থানের ক্ষেত্রে ক্লিনআপের প্রয়োজন হবে
      যদি (ত্রুটি) বিরতি;
      // ***** এই লাইনের প্রবন্ধটি দেখুন
    } যখন (0);
    .. পরিষ্কার জিনিস 2;
  } যখন (0);
  .. পরিষ্কার জিনিস 1;

তবে যদি ফাংশনটি ব্যর্থ হয় কেবল ক্লিনআপটি হওয়ার কথা ছিল, প্রথম টার্গেট লেবেলের ঠিক সামনে gotoরেখে কেসটি পরিচালনা করা যেতে পারে return। উপরের returnকোডটির সাথে চিহ্নিত লাইনে একটি যুক্ত করা প্রয়োজন *****

"সাধারণ ক্ষেত্রে এমনকি পরিষ্কার-পরিচ্ছন্নতা" দৃশ্যে, আমি অন্যান্য বিষয়গুলির মধ্যে / কনস্ট্রাক্টের gotoতুলনায় আরও পরিষ্কার হওয়া হিসাবে বিবেচনা করব কারণ টার্গেট লেবেলগুলি ব্যবহারিকভাবে এবং / কনস্ট্রাক্টের চেয়ে অনেক বেশি "লুক এট এমইই" চিত্কার করে । "ত্রুটি হলে কেবল ত্রুটি" ক্ষেত্রে, বিবৃতিটি পাঠযোগ্যতার দৃষ্টিকোণ থেকে সবচেয়ে খারাপ স্থানে থাকা সমাপ্ত হয় (প্রত্যাবর্তনের বিবৃতি সাধারণত কোনও ফাংশনের শুরুতে হওয়া উচিত, অথবা অন্যথায় "কেমন দেখাচ্ছে" শেষ); একটি হচ্ছে ঠিক আগে একটি লক্ষ্য ট্যাগ আরো অনেক কিছু নির্দ্ধিধায় যে যোগ্যতা পূরণ করে শুধু একটি "লুপ" শেষ হওয়ার আগে এক থাকার চেয়ে।dowhile(0)breakdowhile(0)returnreturn

বিটিডাব্লু, একটি দৃশ্য যেখানে আমি মাঝে মাঝে gotoত্রুটি-পরিচালনা করার জন্য ব্যবহার করি তা একটি switchবিবৃতিতে হয়, যখন একাধিক মামলার কোড একই ত্রুটি কোডটি ভাগ করে দেয়। যদিও আমার সংকলক প্রায়শই একই কোড দিয়ে শেষ হয় যে একাধিক কেস স্বীকৃতি দিতে যথেষ্ট স্মার্ট হতে পারে, আমি মনে করি এটি স্পষ্ট করে বলা:

 পুনরুদ্ধার করুন:
  স্যুইচ (প্যাকেট [0])
  {
    কেস PKT_THIS_OPERATION:
      যদি (সমস্যার শর্ত)
        যাও PACKET_ERROR;
      ... THIS_OPERATION পরিচালনা করুন
      বিরতি;
    কেস PKT_THAT_OPERATION:
      যদি (সমস্যার শর্ত)
        যাও PACKET_ERROR;
      ... হ্যান্ডেল করুন THAT_OPERATION
      বিরতি;
    ...
    কেস PKT_PROCESS_CONDITIONALLY
      যদি (প্যাকেট_ দৈর্ঘ্য <9)
        যাও PACKET_ERROR;
      যদি (প্যাকেট যুক্ত প্যাকেট_কন্ডিশন [4])
      {
        প্যাকেট_ দৈর্ঘ্য - = 5;
        মেমমোভ (প্যাকেট, প্যাকেট + 5, প্যাকেট_ দৈর্ঘ্য);
        যাও REPARSE_PACKET;
      }
      অন্য
      {
        প্যাকেট [0] = PKT_CONDITION_SKIPPED;
        প্যাকেট [4] = প্যাকেট_ দৈর্ঘ্য;
        প্যাকেট_ দৈর্ঘ্য = 5;
        প্যাকেট_স্ট্যাটাস = READY_TO_SEND;
      }
      বিরতি;
    ...
    ডিফল্ট:
    {
     PACKET_ERROR:
      প্যাকেট_অরর_কাউন্ট ++;
      প্যাকেট_ দৈর্ঘ্য = 4;
      প্যাকেট [0] = PKT_ERROR;
      প্যাকেট_স্ট্যাটাস = READY_TO_SEND;
      বিরতি;
    }
  }   

যদিও কেউ এর gotoসাথে বিবৃতিগুলি প্রতিস্থাপন করতে পারে {handle_error(); break;}, এবং মোড়কযুক্ত শর্তযুক্ত-সম্পাদনকারী প্যাকেটটি প্রসেস করার জন্য কেউ একটি do/ while(0)লুপ ব্যবহার করতে পারে continue, তবে আমি সত্যিই এটি ব্যবহার করার চেয়ে পরিষ্কার মনে করি না goto। উপরন্তু, এটা থেকে কোড আউট কপি করতে সম্ভব হতে পারে যখন PACKET_ERRORসর্বত্র goto PACKET_ERRORব্যবহৃত হয়, এবং যখন একটি কম্পাইলার একবার সদৃশ কোড লিখতে এবং যে ভাগ কপি করার জন্য একটি লাফ সঙ্গে সবচেয়ে ঘটনার প্রতিস্থাপন পারে, ব্যবহার gotoএটা নোটিশ জায়গা থেকে সহজ করে তোলে যা প্যাকেটটিকে কিছুটা আলাদাভাবে সেট আপ করে (যেমন "শর্তসাপেক্ষে কার্যকর করুন" নির্দেশনা কার্যকর না করার সিদ্ধান্ত নেয়)।


1

আমি ব্যক্তিগতভাবে "সুরক্ষা সমালোচনামূলক কোড রচনার জন্য দশটি দশটি নিয়ম" এর অনুগামী ।

আমি সেই পাঠ্য থেকে একটি ছোট স্নিপেট অন্তর্ভুক্ত করব যা গোটো সম্পর্কে ভাল ধারণা বলে আমি বিশ্বাস করি illust


বিধি: সমস্ত কোডকে খুব সাধারণ নিয়ন্ত্রণ প্রবাহের নির্মাণের মধ্যে সীমাবদ্ধ করুন - গোটো স্টেটমেন্ট, সেটজ্যাম্প বা লংজ্যাম্প কনস্ট্রাক্টস এবং সরাসরি বা অপ্রত্যক্ষ পুনরাবৃত্তি ব্যবহার করবেন না।

যুক্তি: সরল নিয়ন্ত্রণ প্রবাহটি যাচাইকরণের জন্য শক্তিশালী ক্ষমতায় অনুবাদ করে এবং প্রায়শই উন্নত কোডের স্বচ্ছতার ফলাফল হয়। পুনরাবৃত্তি নিষিদ্ধকরণ সম্ভবত এখানে বৃহত্তম বিস্ময়। পুনরাবৃত্তি ছাড়াই, যদিও আমাদের কাছে অ্যাসাইক্লিক ফাংশন কল গ্রাফ থাকার গ্যারান্টি রয়েছে যা কোড বিশ্লেষকরা ব্যবহার করতে পারেন এবং এটি প্রমাণ করতে সরাসরি সহায়তা করতে পারে যে সমস্ত মৃত্যুদণ্ড কার্যকর করা উচিত যা বাস্তবে আবদ্ধ। (দ্রষ্টব্য যে এই নিয়মের সমস্ত ফাংশনগুলির একক পয়েন্ট ফেরতের দরকার নেই - যদিও এটি প্রায়শই নিয়ন্ত্রণের প্রবাহকেও সহজতর করে There তবে যথেষ্ট ক্ষেত্রে রয়েছে, যদিও প্রাথমিক ত্রুটি ফিরে পাওয়া সহজ সমাধান))


গোটোর ব্যবহার বাতিল করা খারাপ মনে হলেও:

যদি নিয়মগুলি প্রথমে ড্রাকোনিয়ান বলে মনে হয় তবে মনে রাখবেন যে কোডগুলি যাচাই করা আপনার অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে আপনার পরমাণু বিদ্যুৎ কেন্দ্রের বিমানটি নিয়ন্ত্রণ করতে ব্যবহৃত কোডটি ব্যবহার করা সম্ভব they আপনি যেখানে থাকেন থেকে কয়েক মাইল দূরে বা মহাকাশযান যা মহাকাশচারীকে কক্ষপথে নিয়ে যায়। নিয়মগুলি আপনার গাড়ীর সিট-বেল্টের মতো কাজ করে: শুরুতে তারা সম্ভবত কিছুটা অস্বস্তিকর হয় তবে কিছুক্ষণ পরে তাদের ব্যবহার দ্বিতীয়-প্রকৃতির হয়ে যায় এবং সেগুলি ব্যবহার না করা অকল্পনীয় হয়ে ওঠে।


22
এটির সাথে সমস্যাটি হ'ল সম্পূর্ণ নিষেধাজ্ঞার স্বাভাবিক উপায় gotoহ'ল গভীরভাবে নেস্টেড ifs বা লুপগুলিতে কিছু "চালাক" বুলিয়ান ব্যবহার করা। এটি সত্যিই সাহায্য করে না। হতে পারে আপনার সরঞ্জামগুলি আরও ভাল ছাঁটাই করবে তবে আপনি তা করবেন না এবং আপনি আরও গুরুত্বপূর্ণ।
ডোনাল ফেলো

1

আমি সম্মত হলাম যে প্রশ্নটিতে উল্টো অর্থে দেওয়া গোটো ক্লিনআপ বেশিরভাগ কার্যক্রমে জিনিস পরিষ্কার করার সর্বোত্তম উপায়। তবে আমি এটিও উল্লেখ করতে চেয়েছিলাম যে কখনও কখনও আপনি নিজের ফাংশনটি যাইহোক পরিষ্কার করতে চান। এই ক্ষেত্রে আমি নিম্নলিখিত রূপটি ব্যবহার করি যদি (0) {লেবেল:} প্রতিচ্ছবি পরিষ্কার করার প্রক্রিয়াটির সঠিক পয়েন্টে যেতে:

int decode ( char * path_in , char * path_out )
{
  FILE * in , * out ;
  code c ;
  int len ;
  int res = 0  ;
  if ( path_in == NULL )
    in = stdin ;
  else
    {
      if ( ( in = fopen ( path_in , "r" ) ) == NULL )
        goto error_open_file_in ;
    }
  if ( path_out == NULL )
    out = stdout ;
  else
    {
      if ( ( out = fopen ( path_out , "w" ) ) == NULL )
        goto error_open_file_out ;
    }

  if( read_code ( in , & c , & longueur ) )
    goto error_code_construction ;

  if ( decode_h ( in , c , out , longueur ) )
  goto error_decode ;

  if ( 0 ) { error_decode: res = 1 ;}
  free_code ( c ) ;
  if ( 0 ) { error_code_construction: res = 1 ; }
  if ( out != stdout ) fclose ( stdout ) ;
  if ( 0 ) { error_open_file_out: res = 1 ; }
  if ( in != stdin ) fclose ( in ) ;
  if ( 0 ) { error_open_file_in: res = 1 ; }
  return res ;
 }

0

আমার কাছে মনে হচ্ছে cleanup_3এটির ক্লিনআপ করা উচিত, তারপরে কল করুন cleanup_2। একইভাবে, cleanup_2এটি পরিষ্কার করা উচিত, তারপরে ক্লিনআপ_1 কল করুন। এটি প্রদর্শিত হয় যে কোনও সময় আপনি এটি করেন cleanup_[n], এটি cleanup_[n-1]প্রয়োজনীয় হয়, সুতরাং এটি পদ্ধতির দায়িত্ব হওয়া উচিত (যাতে উদাহরণস্বরূপ, cleanup_3কল করা cleanup_2এবং সম্ভবত কোনও ফুটো হওয়ার কারণ ছাড়া কখনও কল করা যায় না ))

গোটোসের পরিবর্তে এই পদ্ধতির প্রেক্ষিতে আপনি কেবল ক্লিনআপ রুটিন কল করবেন, তারপরে ফিরে আসবেন।

gotoপদ্ধতির নয় ভুল বা খারাপ , যদিও, এটা ঠিক এর মূল্য এটি অগত্যা "পরিষ্কার" অভিগমন (এই প্রোগ্রামটিতে) নয়।

আপনি যদি সর্বোত্তম পারফরম্যান্সের সন্ধান করছেন, তবে আমি মনে করি যে gotoসমাধানটি সবচেয়ে ভাল। আমি কেবলমাত্র এটি প্রাসঙ্গিক হিসাবে প্রত্যাশা করব, তবে নির্বাচিত কয়েকটি, পারফরম্যান্স সমালোচনা, অ্যাপ্লিকেশনগুলিতে (যেমন, ডিভাইস ড্রাইভার, এমবেডেড ডিভাইস ইত্যাদি)। অন্যথায়, এটি একটি মাইক্রো-অপ্টিমাইজেশন যা কোড স্বচ্ছতার চেয়ে কম অগ্রাধিকার পেয়েছে।


4
এটি কাটবে না - ক্লিনআপগুলি সংস্থানগুলির জন্য নির্দিষ্ট, যা কেবল এই রুটিনে এই ক্রমে বরাদ্দ করা হয়। অন্য জায়গাগুলিতে এগুলি সম্পর্কিত নয়, সুতরাং অন্য একজনকে কল করা অর্থহীন নয়।
এলি বেন্ডারস্কি

0

আমি মনে করি যে এখানে দেওয়া প্রশ্নটি দেওয়া কোডের প্রতি শ্রদ্ধাবোধজনক।

বিবেচনা:

  1. do_something (), init_stuff () এবং prep_stuff () তারা ব্যর্থ হয়েছে কিনা তা জানতে প্রদর্শিত হয়, যেহেতু তারা এই ক্ষেত্রে মিথ্যা বা শূন্য হয়।
  2. রাষ্ট্র প্রতিষ্ঠার দায়বদ্ধতা এই ফাংশনগুলির দায়িত্ব হিসাবে উপস্থিত বলে মনে হয়, যেহেতু foo () এ সরাসরি কোনও রাষ্ট্র প্রতিষ্ঠিত হচ্ছে না।

অতএব: do_someoming (), init_stuff () এবং প্রস্তুত_stuff () তাদের নিজস্ব সাফাই করা উচিত । একটি পৃথক ক্লিনআপ_1 () ফাংশন থাকা যা ডো_সোমথিংয়ের পরে পরিষ্কার হয়ে যায় () এনক্যাপসুলেশনের দর্শন ভঙ্গ করে। এটি খারাপ নকশা।

যদি তারা নিজের ক্লিনআপ করে থাকে তবে foo () বেশ সহজ হয়ে যায়।

অন্য দিকে. যদি foo () প্রকৃতপক্ষে নিজস্ব রাষ্ট্র তৈরি করে যা ছিন্ন করতে হবে, তবে গোটো উপযুক্ত হবে।


0

আমি যা পছন্দ করেছি তা এখানে:

bool do_something(void **ptr1, void **ptr2)
{
    if (!ptr1 || !ptr2) {
        err("Missing arguments");
        return false;
    }
    bool ret = false;

    //Pointers must be initialized as NULL
    void *some_pointer = NULL, *another_pointer = NULL;

    if (allocate_some_stuff(&some_pointer) != STUFF_OK) {
        err("allocate_some_stuff step1 failed, abort");
        goto out;
    }
    if (allocate_some_stuff(&another_pointer) != STUFF_OK) {
        err("allocate_some_stuff step 2 failed, abort");
        goto out;
    }

    void *some_temporary_malloc = malloc(1000);

    //Do something with the data here
    info("do_something OK");

    ret = true;

    // Assign outputs only on success so we don't end up with
    // dangling pointers
    *ptr1 = some_pointer;
    *ptr2 = another_pointer;
out:
    if (!ret) {
        //We are returning an error, clean up everything
        //deallocate_some_stuff is a NO-OP if pointer is NULL
        deallocate_some_stuff(some_pointer);
        deallocate_some_stuff(another_pointer);
    }
    //this needs to be freed every time
    free(some_temporary_malloc);
    return ret;
}

0

পুরানো আলোচনা, তবে .... "তীর বিরোধী প্যাটার্ন" ব্যবহার এবং স্ট্যাটিক ইনলাইন ফাংশন পরে প্রতিটি নেস্টেড স্তরের encapsulate সম্পর্কে কি? কোডটি দেখতে দেখতে পরিষ্কার, এটি সর্বোত্তম (যখন অনুকূলিতকরণ সক্ষম করা হয়), এবং কোনও গোটো ব্যবহার করা হয় না। সংক্ষেপে, বিভক্ত এবং জয়। উদাহরণের নীচে:

static inline int foo_2(int bar)
{
    int return_value = 0;
    if ( prepare_stuff( bar ) ) {
        return_value = do_the_thing( bar );
    }
    cleanup_3();
    return return_value;
}

static inline int foo_1(int bar)
{
    int return_value = 0;
    if ( init_stuff( bar ) ) {
        return_value = foo_2(bar);
    }
    cleanup_2();
    return return_value;
}

int foo(int bar)
{
    int return_value = 0;
    if (do_something(bar)) {
        return_value = foo_1(bar);
    }
    cleanup_1();
    return return_value;
}

স্থানের দিক থেকে, আমরা স্ট্যাকের তিনগুণ ভেরিয়েবল তৈরি করছি, যা ভাল নয়, তবে এটি -O2 স্ট্যাক থেকে ভেরিয়েবল অপসারণ এবং এই সাধারণ উদাহরণে একটি রেজিস্টার ব্যবহার করার সাথে অদৃশ্য হয়ে যায়। উপরের ব্লকটি দিয়ে যা gcc -S -O2 test.cপেয়েছিলাম তা নীচে ছিল:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 13
    .globl  _foo                    ## -- Begin function foo
    .p2align    4, 0x90
_foo:                                   ## @foo
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    pushq   %r14
    pushq   %rbx
    .cfi_offset %rbx, -32
    .cfi_offset %r14, -24
    movl    %edi, %ebx
    xorl    %r14d, %r14d
    xorl    %eax, %eax
    callq   _do_something
    testl   %eax, %eax
    je  LBB0_6
## %bb.1:
    xorl    %r14d, %r14d
    xorl    %eax, %eax
    movl    %ebx, %edi
    callq   _init_stuff
    testl   %eax, %eax
    je  LBB0_5
## %bb.2:
    xorl    %r14d, %r14d
    xorl    %eax, %eax
    movl    %ebx, %edi
    callq   _prepare_stuff
    testl   %eax, %eax
    je  LBB0_4
## %bb.3:
    xorl    %eax, %eax
    movl    %ebx, %edi
    callq   _do_the_thing
    movl    %eax, %r14d
LBB0_4:
    xorl    %eax, %eax
    callq   _cleanup_3
LBB0_5:
    xorl    %eax, %eax
    callq   _cleanup_2
LBB0_6:
    xorl    %eax, %eax
    callq   _cleanup_1
    movl    %r14d, %eax
    popq    %rbx
    popq    %r14
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function

.subsections_via_symbols

-1

আমি নিম্নলিখিত উদাহরণে বর্ণিত কৌশল ব্যবহার করতে পছন্দ করি ...

struct lnode *insert(char *data, int len, struct lnode *list) {
    struct lnode *p, *q;
    uint8_t good;
    struct {
            uint8_t alloc_node : 1;
            uint8_t alloc_str : 1;
    } cleanup = { 0, 0 };

    // allocate node.
    p = (struct lnode *)malloc(sizeof(struct lnode));
    good = cleanup.alloc_node = (p != NULL);

    // good? then allocate str
    if (good) {
            p->str = (char *)malloc(sizeof(char)*len);
            good = cleanup.alloc_str = (p->str != NULL);
    }

    // good? copy data
    if(good) {
            memcpy ( p->str, data, len );
    }

    // still good? insert in list
    if(good) {
            if(NULL == list) {
                    p->next = NULL;
                    list = p;
            } else {
                    q = list;
                    while(q->next != NULL && good) {
                            // duplicate found--not good
                            good = (strcmp(q->str,p->str) != 0);
                            q = q->next;
                    }
                    if (good) {
                            p->next = q->next;
                            q->next = p;
                    }
            }
    }

    // not-good? cleanup.
    if(!good) {
            if(cleanup.alloc_str)   free(p->str);
            if(cleanup.alloc_node)  free(p);
    }

    // good? return list or else return NULL
    return (good? list: NULL);

}

উত্স: http://blog.staila.com/?p=114


4
ফ্ল্যাগি কোড এবং তীর অ্যান্টি-প্যাটার্ন (আপনার উদাহরণে প্রদর্শিত উভয়) হ'ল দুটি বিষয় যা অযথা কোড জটিল করে তোলে। এগুলিকে ব্যবহার করার জন্য "গোটো ইজ ইজ অশুভ" এর বাইরের কোনও যৌক্তিকতা নেই।
কিংআরডিকাল

-1

Daynix CStepsআর ডি ফাংশনগুলিতে " গোটো সমস্যা " এর অন্য সমাধান হিসাবে আমরা লাইব্রেরিটি ব্যবহার করি ।
দেখুন এখানে এবং এখানে


4
ম্যাক্রো অপব্যবহার (সিএসটিপ্সের মতো) এর ন্যায়বিচারের ব্যবহারের চেয়েও খারাপgoto
কিংআরডিকাল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.