সি কোডে পরিচালনা করার সময় ত্রুটি


152

কোনও সি লাইব্রেরিতে ধারাবাহিক উপায়ে ত্রুটি পরিচালনা করার ক্ষেত্রে ত্রুটি আসে যখন আপনি "সেরা অনুশীলন" হিসাবে বিবেচনা করেন।

দুটি উপায় নিয়ে আমি ভাবছিলাম:

সর্বদা ত্রুটি কোডটি ফিরিয়ে দিন। একটি সাধারণ ক্রিয়াকলাপটি এর মতো দেখায়:

MYAPI_ERROR getObjectSize(MYAPIHandle h, int* returnedSize);

সর্বদা একটি ত্রুটি পয়েন্টার পদ্ধতির সরবরাহ করে:

int getObjectSize(MYAPIHandle h, MYAPI_ERROR* returnedError);

প্রথম পদ্ধতির ব্যবহার করার সময় এই জাতীয় কোড লেখা সম্ভব যেখানে ত্রুটি পরিচালনার চেকটি সরাসরি ফাংশন কলটিতে রাখা হয়:

int size;
if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
  // Error handling
}

যা এখানে ত্রুটি পরিচালনার কোডের চেয়ে ভাল দেখাচ্ছে।

MYAPIError error;
int size;
size = getObjectSize(h, &error);
if(error != MYAPI_SUCCESS) {
    // Error handling
}

তবে আমি মনে করি তথ্য ফেরত দেওয়ার জন্য রিটার্ন মান ব্যবহার করা কোডটি আরও পঠনযোগ্য করে তোলে, এটি স্পষ্ট যে দ্বিতীয় উদাহরণে আকারের পরিবর্তনশীলটিতে কিছু লেখা হয়েছিল।

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

সম্পাদনা: এ সম্পর্কে সি ++ সুনির্দিষ্ট ধারণাগুলি যতক্ষণ না এই মুহুর্তে এটি আমার পক্ষে বিকল্প নয় ততক্ষণ তারা ব্যতিক্রমগুলি জড়িত না হওয়ার বিষয়ে শুনতে আগ্রহী হবে ...


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

উত্তর:


74

আমি ত্রুটিটি রিটার্ন-ভ্যালু ওয়ে হিসাবে পছন্দ করি। আপনি যদি এপিআই ডিজাইন করে থাকেন এবং আপনি নিজের লাইব্রেরিটিকে যতটা সম্ভব বেদনাদায়ক ব্যবহার করতে চান তবে এই সংযোজনগুলি সম্পর্কে ভাবুন:

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

  • এমন একটি ফাংশন সরবরাহ করুন যা ত্রুটিগুলিকে মানুষের পাঠযোগ্য কিছুতে রূপান্তর করে। সহজ হতে পারে। শুধু ত্রুটি-এনাম ইন, চার্জ * আউট।

  • আমি জানি এই ধারণাটি মাল্টিথ্রেটেড ব্যবহারকে কিছুটা কঠিন করে তোলে তবে অ্যাপ্লিকেশন প্রোগ্রামার যদি একটি বিশ্বব্যাপী ত্রুটি-কলব্যাক সেট করতে পারে তবে এটি ভাল হবে। এইভাবে তারা বাগ-হান্ট সেশনের সময় কলব্যাকের মধ্যে ব্রেক ব্রেকপয়েন্ট স্থাপন করতে সক্ষম হবে।

আশা করি এটা সাহায্য করবে.


5
আপনি কেন বলছেন, "এই ধারণাটি বহু-থ্রেডযুক্ত ব্যবহারকে কিছুটা কঠিন করে তোলে।" মাল্টি থ্রেডিংয়ের মাধ্যমে কোন অংশটি কঠিন হয়ে উঠেছে? আপনি একটি দ্রুত উদাহরণ দিতে পারেন?
সাইয়েদহুসাইন

1
@ ক্রিপটিককোডার সরলভাবে বলেছেন: যে কোনও থ্রেড প্রসঙ্গে বিশ্বব্যাপী ত্রুটি কলব্যাক শুরু করা যেতে পারে। আপনি যদি কেবল ত্রুটিটি মুদ্রণ করেন তবে কোনও সমস্যার মুখোমুখি হবেন না। আপনি যদি সমস্যাগুলি সংশোধন করার চেষ্টা করেন তবে আপনাকে খুঁজে বের করতে হবে যে কোন কলিং থ্রেড ত্রুটির কারণে ঘটেছে এবং এটি সমস্যাগুলিকে কঠিন করে তোলে।
নিলস পিপেনব্রিংক

9
আপনি যদি ত্রুটির আরও বিশদটি যোগাযোগ করতে চান তবে কী হবে? যেমন আপনার একটি পার্সার ত্রুটি রয়েছে এবং সিনট্যাক্স ত্রুটির লাইন নম্বর এবং কলাম এবং সমস্ত সুন্দরভাবে মুদ্রণের একটি উপায় সরবরাহ করতে চান।
পানজী

1
@ পাঞ্জি তারপর আপনার অবশ্যই স্পষ্টভাবে কোনও স্ট্রাক্ট ফিরিয়ে আনতে হবে (বা স্ট্রাকট সত্যই বড় হলে আউট পয়েন্টার ব্যবহার করুন) এবং স্ট্রিং হিসাবে স্ট্রাক্টটি ফর্ম্যাট করার জন্য একটি ফাংশন থাকতে হবে।
উইঙ্গার সেন্ডন

আমি এখানে কোডে আপনার প্রথম 2 টি বুলেট প্রদর্শন করি: stackoverflow.com/questions/385975/error-handling-in-c-code/…
গ্যাব্রিয়েল স্ট্যাপলস

92

আমি উভয় পদ্ধতির ব্যবহার করেছি এবং তারা উভয়ই আমার পক্ষে ভাল কাজ করেছে। আমি যে কোনও একটি ব্যবহার করি না কেন, আমি সর্বদা এই নীতিটি প্রয়োগ করার চেষ্টা করি:

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

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


1
সি-তে দাবির উদাহরণ পেয়েছেন? (আমি সি তে সবুজ)
থমথম

এটি সাধারণত যতটা সহজ assert(X)X হ'ল এমন কোনও বৈধ সি স্টেটমেন্ট যা আপনি সত্য হতে চান। দেখতে stackoverflow.com/q/1571340/10396
আশেল্লি

14
উঘ, গ্রন্থাগারের কোডে কখনই আসক্তি ব্যবহার করবেন না ! এছাড়াও, অন্যদের মতো কোডের এক টুকরোতে ত্রুটি পরিচালনার বিভিন্ন
স্টাইলকে

10
শৈলীর মিশ্রণ না করার বিষয়ে আমি অবশ্যই একমত। দৃser়তার সাথে আপনার যুক্তি সম্পর্কে আমি আগ্রহী। আমার ফাংশন ডকুমেন্টেশনে যদি বলা হয় যে "আর্গুমেন্ট এক্স অবশ্যই নল হওয়া উচিত নয়" বা "ওয়াই অবশ্যই এই এনামের সদস্য হওয়া উচিত", এর সাথে assert(X!=NULL);বা assert(Y<enumtype_MAX);কী ভুল ? প্রোগ্রামারগুলিতে এই উত্তরটি দেখুন এবং আমি কেন এটি সঠিক পথ বলে মনে করি সে সম্পর্কে আরও তথ্যের জন্য এটির সাথে লিঙ্ক করা প্রশ্নটি দেখুন।
এশেলি

8
@ শ্যাশলি এই সমস্যাগুলির সাথে দাবি করে যে তারা সাধারণত সেখানে মুক্তি দেয় না।
কলমারিয়াস 10'15

29

সাধারণ সি (এবং সি ++) ত্রুটি পরিচালনার কৌশলগুলির প্রত্যেকটি কখন ব্যবহার করবেন তার জন্য সুপারিশ সহ সিএমইউর সিইআরটি থেকে স্লাইডগুলির একটি দুর্দান্ত সেট রয়েছে । সেরা স্লাইডগুলির মধ্যে একটি হ'ল এই সিদ্ধান্ত গাছ:

সিদ্ধান্ত গাছ পরিচালনা করার সময় ত্রুটি

আমি ব্যক্তিগতভাবে এই ফ্লোকার্ট সম্পর্কে দুটি জিনিস পরিবর্তন করব।

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

দ্বিতীয়ত, সি ++ এ ব্যতিক্রমগুলি ব্যবহার করা সর্বদা উপযুক্ত নয় । ব্যতিক্রমগুলি ভাল কারণ তারা ত্রুটি পরিচালনায় উত্সর্গীকৃত উত্স কোডের পরিমাণ হ্রাস করতে পারে, তারা বেশিরভাগ ক্ষেত্রে ফাংশন স্বাক্ষরগুলিকে প্রভাবিত করে না এবং তারা কলস্ট্যাকটি কী ডেটা পাস করতে পারে সে বিষয়ে তারা খুব নমনীয়। অন্যদিকে, ব্যতিক্রম কয়েকটি কারণে সঠিক পছন্দ নাও হতে পারে:

  1. সি ++ ব্যতিক্রমগুলির খুব নির্দিষ্ট শব্দার্থক শব্দ রয়েছে। আপনি যদি এই শব্দার্থবিজ্ঞানগুলি না চান, তবে সি ++ ব্যতিক্রমগুলি খারাপ পছন্দ। নিক্ষেপ হওয়ার পরে অবিলম্বে একটি ব্যতিক্রম মোকাবেলা করতে হবে এবং কলটিস্ট্যাকটি কয়েক স্তরের আনইন্ডাইন্ড করার জন্য ত্রুটির প্রয়োজন হবে এমন ডিজাইনের পক্ষে রয়েছে।

  2. সি ++ ফাংশনগুলি যে ব্যতিক্রমগুলি ফেলে দেয় সেগুলি পরে ব্যতিক্রমগুলি ছুঁড়ে না দেওয়ার জন্য আবৃত করা যায় না, অন্তত যাইহোক ব্যতিক্রমগুলির পুরো মূল্য প্রদান না করে নয়। যে ক্রিয়াকলাপগুলি ত্রুটি কোডগুলি ফেরত দেয় সেগুলি আরও নমনীয় করে সি ++ ব্যতিক্রম নিক্ষেপ করতে মোড়ানো যেতে পারে। সি ++ এর newএকটি নন-নিক্ষেপযোগ্য ভেরিয়েন্ট সরবরাহ করে এই অধিকারটি পাওয়া যায়।

  3. সি ++ ব্যতিক্রমগুলি তুলনামূলকভাবে ব্যয়বহুল তবে ব্যতিক্রমগুলি বোধগম্যভাবে ব্যবহারযোগ্য প্রোগ্রামগুলির জন্য এই ডাউনসাইডটি বেশিরভাগ ক্ষেত্রেই ওভারলাউন্ড হয়। কোনও প্রোগ্রামের কোনও কোডপথের ক্ষেত্রে ব্যতিক্রম ছোঁড়া উচিত নয় যেখানে কর্মক্ষমতা একটি উদ্বেগ is আপনার প্রোগ্রামটি তত দ্রুত ত্রুটির খবর দিতে এবং প্রস্থান করতে পারে তা বিবেচ্য নয়।

  4. কখনও কখনও সি ++ ব্যতিক্রম পাওয়া যায় না। হয় সেগুলি কারও সি ​​++ প্রয়োগের ক্ষেত্রে আক্ষরিকরূপে উপলব্ধ নয়, বা এর কোড নির্দেশিকা তাদের নিষিদ্ধ করে।


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


5
আপনি লক্ষ করতে পারেন যে গুগলের সি ++ কোডিং মানগুলি এখনও বলে যে আমরা সি ++ ব্যতিক্রম ব্যবহার করি না।
জোনাথন লেফলার

19

আমি যখনই কোনও লাইব্রেরি তৈরি করি তখন আমি প্রথম পদ্ধতির ব্যবহার করি। রিটার্ন কোড হিসাবে টাইপডেফড এনাম ব্যবহার করার বিভিন্ন সুবিধা রয়েছে।

  • যদি ফাংশনটি আরও জটিল আউটপুট যেমন একটি অ্যারে দেয় এবং এর দৈর্ঘ্য দেয় তবে আপনাকে ফিরে আসার জন্য স্বেচ্ছাসেবী কাঠামো তৈরি করার দরকার নেই।

    rc = func(..., int **return_array, size_t *array_length);
  • এটি সহজ, মানক ত্রুটি পরিচালনা করার অনুমতি দেয়।

    if ((rc = func(...)) != API_SUCCESS) {
       /* Error Handling */
    }
  • এটি লাইব্রেরির ফাংশনে সাধারণ ত্রুটি পরিচালনা করার অনুমতি দেয়।

    /* Check for valid arguments */
    if (NULL == return_array || NULL == array_length)
        return API_INVALID_ARGS;
  • একটি টাইপফিডযুক্ত এনুম ব্যবহার করে এনব নামটি ডিবাগারে দৃশ্যমান হওয়ার অনুমতি দেয়। এটি একটি হেডার ফাইলের সাথে নিয়মিত পরামর্শের প্রয়োজন ছাড়াই সহজ ডিবাগিংয়ের অনুমতি দেয়। এই এনামটিকে স্ট্রিংয়ে অনুবাদ করার জন্য একটি ফাংশন থাকাও সহায়ক।

ব্যবহার করা পদ্ধতির নির্বিশেষে সবচেয়ে গুরুত্বপূর্ণ ইস্যুটি ধারাবাহিক হওয়া consistent এটি ফাংশন এবং যুক্তি নামকরণ, যুক্তি ক্রম এবং ত্রুটি পরিচালনার ক্ষেত্রে প্রযোজ্য।


9

সেটজ্যাম্প ব্যবহার করুন ।

http://en.wikipedia.org/wiki/Setjmp.h

http://aszt.inf.elte.hu/~gsd/halado_cpp/ch02s03.html

http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html

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

jmp_buf x;

void f()
{
    longjmp(x,5); // throw 5;
}

int main()
{
    // output of this program is 5.

    int i = 0;

    if ( (i = setjmp(x)) == 0 )// try{
    {
        f();
    } // } --> end of try{
    else // catch(i){
    {
        switch( i )
        {
        case  1:
        case  2:
        default: fprintf( stdout, "error code = %d\n", i); break;
        }
    } // } --> end of catch(i){
    return 0;
}

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

#define TRY do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){
#define CATCH } else {
#define ETRY } }while(0)
#define THROW longjmp(ex_buf__, 1)

int
main(int argc, char** argv)
{
   TRY
   {
      printf("In Try Statement\n");
      THROW;
      printf("I do not appear\n");
   }
   CATCH
   {
      printf("Got Exception!\n");
   }
   ETRY;

   return 0;
}

2
কোডের দ্বিতীয় ব্লকটি উত্তরটির শীর্ষে রেফারেন্সযুক্ত ফ্রান্সেস্কো নিদিতোর পৃষ্ঠায় কোডটির আগের সংস্করণের ভিত্তিতে তৈরি । ETRYএই উত্তরটি লেখা হওয়ার পরে কোডটি সংশোধন করা হয়েছে।
জোনাথন লেফলার

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

1
আপনি যদি মেমোরিটিকে ম্যালোকল করেন এবং তারপরে ফেলে দেন তবে স্মৃতিটি চিরতরে ফুটো হয়ে যাবে। এছাড়াও setjmpদামী এমনকি যদি কোন ত্রুটি কি কখনো ফেলা হয় এটা বেশ CPU- র সময় এবং স্ট্যাকের স্থান একটি বিট গ্রাস করবে। উইন্ডোজের জন্য জিসিসি ব্যবহার করার সময়, আপনি সি ++ এর জন্য বিভিন্ন ব্যতিক্রম হ্যান্ডলিং পদ্ধতির মধ্যে বেছে নিতে পারেন, এর মধ্যে একটি বেস রয়েছে setjmpএবং এটি আপনার কোডটিকে অনুশীলনে 30% ধীর করে তোলে।
মক্কি

7

আমি ব্যক্তিগতভাবে পূর্বের পদ্ধতির পছন্দ করি (একটি ত্রুটি সূচক ফেরানো)।

যেখানে প্রয়োজনীয় সেখানে রিটার্নের ফলাফলটি কেবল একটি ত্রুটি ঘটেছে তা নির্দেশ করবে এবং সঠিক ত্রুটি খুঁজে পেতে অন্য ফাংশন ব্যবহার করা হবে।

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

আমি এমন কোনও লাইব্রেরি ভাবতে পারি না যা আমি ব্যবহার করেছি যা পয়েন্টার হিসাবে পাস হওয়া একটি ত্রুটিযুক্ত বস্তুর সাথে পরবর্তী পদ্ধতির জন্য যায়। stdio, ইত্যাদি সমস্ত একটি ফেরতের মান দিয়ে যায়।


1
রেকর্ডের জন্য, আমি যে লাইব্রেরিটির উত্তরোত্তর পদ্ধতির ব্যবহার দেখেছি তা হ'ল মায়া প্রোগ্রামিং এপিআই। এটি সি এর পরিবর্তে সি ++ গ্রন্থাগার। এটির ত্রুটিগুলি কীভাবে পরিচালনা করে এটির ক্ষেত্রে এটি বেশ বেমানান।
Laserallan

1
স্ট্রিটড ভুলে যাবেন না, ঠিক আছে, শেষ যুক্তিটি কেবল ত্রুটিগুলি নির্দেশ করার জন্য নয়, এটি এটিও করে।
কুইনমার্স

7

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


7

ত্রুটি কোডটি রিটার্নিং সি এর মধ্যে ত্রুটি পরিচালনা করার জন্য সাধারণ পদ্ধতির is

তবে সম্প্রতি আমরা বহির্গামী ত্রুটি পয়েন্টার পদ্ধতিরও পরীক্ষা করেছি।

রিটার্ন মান পদ্ধতির তুলনায় এর কিছু সুবিধা রয়েছে:

  • আপনি রিটার্ন মানটি আরও অর্থপূর্ণ উদ্দেশ্যে ব্যবহার করতে পারেন।

  • সেই ত্রুটি পরামিতিটি লিখতে আপনাকে ত্রুটিটি পরিচালনা করতে বা এটি প্রচার করতে মনে করিয়ে দেয়। (আপনি কখনই এর রিটার্ন ভ্যালু চেক করতে ভুলে fcloseযাবেন না?)

  • আপনি যদি কোনও ত্রুটি পয়েন্টার ব্যবহার করেন তবে আপনি ফাংশনগুলি কল করার সাথে সাথে এটি পাস করতে পারেন। যদি কোনও ফাংশন এটি সেট করে, মানটি হারাবে না।

  • ত্রুটি ভেরিয়েবলের উপর ডেটা ব্রেকপয়েন্ট স্থাপন করে, ত্রুটিটি প্রথম কোথায় ঘটেছিল তা আপনি ধরতে পারেন। শর্তযুক্ত ব্রেকপয়েন্টটি সেট করে আপনি নির্দিষ্ট ত্রুটিগুলিও ধরতে পারেন।

  • আপনি সমস্ত ত্রুটি পরিচালনা করেন কিনা তা চেকটিকে স্বয়ংক্রিয়করণ করা সহজ করে তোলে। কোড কনভেনশন আপনাকে আপনার ত্রুটি নির্দেশক হিসাবে কল করতে বাধ্য করতে পারে errএবং এটি অবশ্যই শেষ যুক্তি। সুতরাং স্ক্রিপ্টটি স্ট্রিংয়ের সাথে মেলে err);তারপরে এটি অনুসরণ করা হয়েছে কিনা তা পরীক্ষা করতে পারেন if (*err। আসলে অনুশীলনে আমরা একটি ম্যাক্রো তৈরি করেছি CER(চেক এরর রিটার্ন) এবং CEG(চেক এরর গোটো)। সুতরাং যখন আমরা কেবল ত্রুটি ফিরিয়ে দিতে চাই তখন আপনার এটিকে সর্বদা টাইপ করার দরকার নেই এবং দৃশ্যমান বিশৃঙ্খলা হ্রাস করতে পারে।

আমাদের কোডে সমস্ত ফাংশনের এই বহির্গামী প্যারামিটারটি নেই। এই বহির্গামী প্যারামিটার জিনিসটি এমন ক্ষেত্রে ব্যবহৃত হয় যেখানে আপনি সাধারণত ব্যতিক্রম নষ্ট করেন।


6

এর আগে আমি অনেক সি প্রোগ্রামিং করেছি। এবং আমি সত্যই ত্রুটি কোডের রিটার্ন মানকে মূল্যায়ন করেছি। তবে এর বেশ কয়েকটি সম্ভাব্য সমস্যা রয়েছে:

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

2
দ্বিতীয় সমস্যাটি সঠিক সংকলক সতর্কতা স্তর, সঠিক কোড পর্যালোচনা ব্যবস্থা এবং স্ট্যাটিক কোড বিশ্লেষক সরঞ্জামগুলির দ্বারা সমাধান করা যেতে পারে।
ইলিয়া

1
আপনি নীতির উপরও কাজ করতে পারেন: যদি API ফাংশনটি কল করা হয় এবং ফেরতের মানটি পরীক্ষা না করা হয় তবে একটি বাগ রয়েছে।
জোনাথন লেফলার

6

ইউনিক্স পন্থাটি আপনার দ্বিতীয় পরামর্শের সাথে সাদৃশ্যপূর্ণ। ফলাফল বা একক "এটি ভুল হয়ে গেছে" মানটি ফিরিয়ে দিন। উদাহরণস্বরূপ, ওপেন সাফল্যে ফাইলের বিবরণকারী বা ব্যর্থতার পরে -1 প্রদান করবে। ব্যর্থতার পরে এটিও সেট হয় errno, কোন ব্যর্থতা ঘটেছে তা নির্দেশ করার জন্য একটি বহিরাগত বৈশ্বিক পূর্ণসংখ্যা

এটির মূল্য কী, এর জন্য কোকোও একই ধরণের পন্থা অবলম্বন করে চলেছে। বেশ কয়েকটি পদ্ধতি BOOL ফিরিয়ে দেয় এবং একটি NSError **পরামিতি নেয়, যাতে ব্যর্থতার পরে তারা ত্রুটি সেট করে এবং কোনও ফিরিয়ে দেয় না। তারপরে ত্রুটি পরিচালনার মতো দেখাচ্ছে:

NSError *error = nil;
if ([myThing doThingError: &error] == NO)
{
  // error handling
}

যা আপনার দুটি বিকল্পের মধ্যে কোথাও রয়েছে :-)।


5

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


আমাকে জানতে দেওয়ার জন্য ধন্যবাদ। এটি দেখতে আকর্ষণীয় ছিল।
Laserallan

5

এখানে একটি পদ্ধতির যা আমি মনে করি আকর্ষণীয়, যখন কিছু শৃঙ্খলা প্রয়োজন।

এটি হ্যান্ডেল-প্রকারের ভেরিয়েবল হ'ল সেই উদাহরণটি যা সমস্ত API ফাংশন পরিচালনা করে।

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

উদাহরণ:

MyHandle * h = MyApiCreateHandle();

/* first call checks for pointer nullity, since we cannot retrieve error code
   on a NULL pointer */
if (h == NULL)
     return 0; 

/* from here h is a valid handle */

/* get a pointer to the error struct that will be updated with each call */
MyApiError * err = MyApiGetError(h);


MyApiFileDescriptor * fd = MyApiOpenFile("/path/to/file.ext");

/* we want to know what can go wrong */
if (err->code != MyApi_ERROR_OK) {
    fprintf(stderr, "(%d) %s\n", err->code, err->message);
    MyApiDestroy(h);
    return 0;
}

MyApiRecord record;

/* here the API could refuse to execute the operation if the previous one
   yielded an error, and eventually close the file descriptor itself if
   the error is not recoverable */
MyApiReadFileRecord(h, &record, sizeof(record));

/* we want to know what can go wrong, here using a macro checking for failure */
if (MyApi_FAILED(err)) {
    fprintf(stderr, "(%d) %s\n", err->code, err->message);
    MyApiDestroy(h);
    return 0;
}

4

প্রথম পদ্ধতির উন্নত আইএমএইচও:

  • ফাংশনটি সেভাবে লেখা সহজ। আপনি যখন ফাংশনের মাঝখানে কোনও ত্রুটি লক্ষ্য করেন আপনি কেবল একটি ত্রুটির মান ফিরিয়ে দেন। দ্বিতীয় পদ্ধতির আপনাকে কোনও একটি পরামিতিগুলিতে ত্রুটির মান নির্ধারণ করতে হবে এবং তারপরে কোনও কিছু ফেরত দিতে হবে .... তবে আপনি কী ফিরিয়ে আনবেন - আপনার সঠিক মান নেই এবং আপনার ত্রুটির মান ফিরে আসে না।
  • এটি আরও জনপ্রিয় তাই এটি বোঝা, বজায় রাখা সহজ হবে

4

আমি অবশ্যই প্রথম সমাধানটি পছন্দ করি:

int size;
if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
  // Error handling
}

আমি এটিকে কিছুটা সংশোধন করব:

int size;
MYAPIError rc;

rc = getObjectSize(h, &size)
if ( rc != MYAPI_SUCCESS) {
  // Error handling
}

অতিরিক্ত হিসাবে আমি কখনই বৈধ রিটার্ন মানটিকে ত্রুটির সাথে মিশ্রিত করব না যদিও বর্তমানে ফাংশনটির সুযোগ আপনাকে এটি করার অনুমতি দিচ্ছে, ভবিষ্যতে কোন পদ্ধতিতে কার্যকর হবে তা আপনি কখনই জানেন না।

এবং যদি আমরা ইতিমধ্যে ত্রুটি পরিচালনার বিষয়ে কথা বলি তবে আমি goto Error;ত্রুটি পরিচালনার কোড হিসাবে প্রস্তাব দেব , যদি না কিছু undoফাংশন সঠিকভাবে ত্রুটি পরিচালনার জন্য হ্যান্ডেল করার জন্য ডাকা না যায়।


3

আপনার ত্রুটি ফিরিয়ে দেওয়ার পরিবর্তে আপনি কী করতে পারেন এবং এভাবে আপনার ফাংশন সহ ডেটা ফেরত দিতে নিষেধ করছেন তা আপনার রিটার্নের ধরণের জন্য একটি মোড়ক ব্যবহার করছে:

typedef struct {
    enum {SUCCESS, ERROR} status;
    union {
        int errCode;
        MyType value;
    } ret;
} MyTypeWrapper;

তারপরে, তথ্যের জন্য:

MyTypeWrapper MYAPIFunction(MYAPIHandle h) {
    MyTypeWrapper wrapper;
    // [...]
    // If there is an error somewhere:
    wrapper.status = ERROR;
    wrapper.ret.errCode = MY_ERROR_CODE;

    // Everything went well:
    wrapper.status = SUCCESS;
    wrapper.ret.value = myProcessedData;
    return wrapper;
} 

দয়া করে নোট করুন যে নিম্নলিখিত পদ্ধতির সাহায্যে মোড়কটির মাইটাইপ প্লাস ওয়ান বাইট (বেশিরভাগ সংকলকগুলিতে) থাকবে যা বেশ লাভজনক; এবং আপনি যখন আপনার ফাংশনটি কল করবেন তখন ( returnedSizeবা returnedErrorআপনি যে দুটি পদ্ধতি উপস্থাপন করেছেন) আপনাকে স্ট্যাকের উপরে আর একটি যুক্তি চাপতে হবে না


3

নীল পাইপেনব্রিংকের উত্তরের প্রথম দুটি গুলি এখানে প্রদর্শন করার জন্য একটি সাধারণ প্রোগ্রাম ।

তার প্রথম দুটি গুলি হ'ল:

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

  • এমন একটি ফাংশন সরবরাহ করুন যা ত্রুটিগুলিকে মানুষের পাঠযোগ্য কিছুতে রূপান্তর করে। সহজ হতে পারে। শুধু ত্রুটি-এনাম ইন, চার্জ * আউট।

ধরুন আপনি নামের একটি মডিউল লিখেছেন mymoduleপ্রথমে, mymodule.h এ, আপনি আপনার এনাম-ভিত্তিক ত্রুটি কোডগুলি সংজ্ঞায়িত করেন এবং আপনি কিছু কোড ত্রুটিগুলি লিখে থাকেন যা এই কোডগুলির সাথে মিলে যায় correspond এখানে আমি সি স্ট্রিংগুলির একটি অ্যারে ( char *) ব্যবহার করছি , যা কেবলমাত্র তখনই কার্যকর হয় যদি আপনার প্রথম এনাম-ভিত্তিক ত্রুটি কোডটির মান 0 থাকে এবং আপনি তার পরে সংখ্যাগুলি হেরফের করেন না। যদি আপনি শূন্যস্থান বা অন্য প্রারম্ভিক মানগুলির সাথে ত্রুটি কোড নম্বর ব্যবহার করেন তবে আপনাকে কেবল একটি ম্যাপ করা সি-স্ট্রিং অ্যারে ব্যবহার করে (যেমন আমি নীচে করব) কোনও ফাংশন যা সুইচ স্টেটমেন্ট ব্যবহার করে তা ব্যবহার করতে বা যদি / অন্যথায় বিবৃতি ব্যবহার করতে হয় তবে পরিবর্তন করতে হবে এনাম ত্রুটি কোডগুলি থেকে মুদ্রণযোগ্য সি স্ট্রিংগুলিতে মানচিত্র (যা আমি প্রদর্শন করি না)। সিদ্ধান্ত আপনার.

mymodule.h

/// @brief Error codes for library "mymodule"
typedef enum mymodule_error_e
{
    /// No error
    MYMODULE_ERROR_OK = 0,
    
    /// Invalid arguments (ex: NULL pointer where a valid pointer is required)
    MYMODULE_ERROR_INVARG,

    /// Out of memory (RAM)
    MYMODULE_ERROR_NOMEM,

    /// Make up your error codes as you see fit
    MYMODULE_ERROR_MYERROR, 

    // etc etc
    
    /// Total # of errors in this list (NOT AN ACTUAL ERROR CODE);
    /// NOTE: that for this to work, it assumes your first error code is value 0 and you let it naturally 
    /// increment from there, as is done above, without explicitly altering any error values above
    MYMODULE_ERROR_COUNT,
} mymodule_error_t;

// Array of strings to map enum error types to printable strings
// - see important NOTE above!
const char* const MYMODULE_ERROR_STRS[] = 
{
    "MYMODULE_ERROR_OK",
    "MYMODULE_ERROR_INVARG",
    "MYMODULE_ERROR_NOMEM",
    "MYMODULE_ERROR_MYERROR",
};

// To get a printable error string
const char* mymodule_error_str(mymodule_error_t err);

// Other functions in mymodule
mymodule_error_t mymodule_func1(void);
mymodule_error_t mymodule_func2(void);
mymodule_error_t mymodule_func3(void);

mymodule.c এ এনাম ত্রুটি কোডগুলি থেকে মুদ্রণযোগ্য সি স্ট্রিংগুলিতে মানচিত্রের জন্য আমার ম্যাপিং ফাংশন রয়েছে:

mymodule.c

#include <stdio.h>

/// @brief      Function to get a printable string from an enum error type
/// @param[in]  err     a valid error code for this module
/// @return     A printable C string corresponding to the error code input above, or NULL if an invalid error code
///             was passed in
const char* mymodule_error_str(mymodule_error_t err)
{
    const char* err_str = NULL;

    // Ensure error codes are within the valid array index range
    if (err >= MYMODULE_ERROR_COUNT)
    {
        goto done;
    }

    err_str = MYMODULE_ERROR_STRS[err];

done:
    return err_str;
}

// Let's just make some empty dummy functions to return some errors; fill these in as appropriate for your 
// library module

mymodule_error_t mymodule_func1(void)
{
    return MYMODULE_ERROR_OK;
}

mymodule_error_t mymodule_func2(void)
{
    return MYMODULE_ERROR_INVARG;
}

mymodule_error_t mymodule_func3(void)
{
    return MYMODULE_ERROR_MYERROR;
}

কিছুটা ফাংশন কল করে এবং সেগুলি থেকে কিছু ত্রুটি কোডগুলি মুদ্রণ করে তা প্রদর্শনের জন্য মেইন.সি. তে একটি পরীক্ষা প্রোগ্রাম রয়েছে:

main.c

#include <stdio.h>

int main()
{
    printf("Demonstration of enum-based error codes in C (or C++)\n");

    printf("err code from mymodule_func1() = %s\n", mymodule_error_str(mymodule_func1()));
    printf("err code from mymodule_func2() = %s\n", mymodule_error_str(mymodule_func2()));
    printf("err code from mymodule_func3() = %s\n", mymodule_error_str(mymodule_func3()));

    return 0;
}

আউটপুট:

সি enum ভিত্তিক ত্রুটি কোডের (অথবা সি ++) বিক্ষোভের
mymodule_func1 থেকে দূরে সরে যায় কোড () = MYMODULE_ERROR_OK
mymodule_func2 থেকে দূরে সরে যায় কোড () = MYMODULE_ERROR_INVARG
মাত্রই ভুল করে mymodule_func3 থেকে কোড () = MYMODULE_ERROR_MYERROR

তথ্যসূত্র:

আপনি এই কোডটি এখানে নিজে চালাতে পারেন: https://onlinegdb.com/ByEbKLupS


2

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

আমি ব্যক্তিগতভাবে ত্রুটি কোডগুলি শূন্য হিসাবে no_error সহ negativeণাত্মক পূর্ণসংখ্যার হিসাবে ফেরত পাঠিয়েছি , তবে এটি আপনাকে নিম্নলিখিত নিম্নলিখিত বাগের সাথে ছেড়ে দেয়

if (MyFunc())
 DoSomething();

একটি বিকল্প হ'ল ব্যর্থতা সর্বদা শূন্য হিসাবে ফিরে আসে এবং আসল ত্রুটির বিবরণ দেওয়ার জন্য একটি লাস্টআরার () ফাংশন ব্যবহার করে।


2

আমি বেশ কয়েকবার এই প্রশ্নোত্তর নিয়ে ছুটে এসেছি এবং আরও বিস্তৃত উত্তর দিতে চাইছি। আমি মনে করি এটির কল্পনা করার সর্বোত্তম উপায় হ'ল কলকে কীভাবে ত্রুটি ফিরে পাওয়া যায় এবং আপনি কী ফিরে আসেন।

কিভাবে

একটি ফাংশন থেকে তথ্য ফেরত দেওয়ার জন্য 3 টি উপায় রয়েছে:

  1. ফেরত মূল্য
  2. আর্গুমেন্ট (গুলি)
  3. ব্যান্ডের বাইরে, এতে নন-লোকাল গোতো (সেটজ্যাম্প / লংজ্যাম্প), ফাইল বা গ্লোবাল স্কোপড ভেরিয়েবলগুলি, ফাইল সিস্টেম ইত্যাদি অন্তর্ভুক্ত রয়েছে includes

ফেরত মূল্য

আপনি কেবলমাত্র একক বস্তু হিসাবে মান ফিরিয়ে দিতে পারেন তবে এটি একটি স্বেচ্ছাসেবী জটিল হতে পারে। এখানে ত্রুটি ফিরে আসার একটি উদাহরণ:

  enum error hold_my_beer();

রিটার্ন মানগুলির একটি সুবিধা হ'ল এটি কম অনুপ্রেরণামূলক ত্রুটি পরিচালনার জন্য কলগুলিতে শৃঙ্খলাবদ্ধ করে:

  !hold_my_beer() &&
  !hold_my_cigarette() &&
  !hold_my_pants() ||
  abort();

এটি কেবল পঠনযোগ্যতা সম্পর্কে নয়, একই ধরণের ফাংশন পয়েন্টারগুলির একটি অ্যারে প্রক্রিয়াকরণের অনুমতি দিতে পারে।

আর্গুমেন্ট (গুলি)

আপনি আর্গুমেন্টের মাধ্যমে একাধিক বস্তুর মাধ্যমে আরও বেশি ফিরে আসতে পারেন, তবে সেরা অনুশীলনটি যুক্তিগুলির মোট সংখ্যা কম রাখার পরামর্শ দেয় (বলুন, <= 4):

void look_ma(enum error *e, char *what_broke);

enum error e;
look_ma(e);
if(e == FURNITURE) {
  reorder(what_broke);
} else if(e == SELF) {
  tell_doctor(what_broke);
}

ব্যান্ড আউট

সেটজ্যাম্প () এর সাহায্যে আপনি একটি স্থান নির্ধারণ করে এবং কীভাবে আপনি কোনও মান মান হ্যান্ডেল করতে চান এবং আপনি লংজ্যাম্প () এর মাধ্যমে সেই স্থানটিতে নিয়ন্ত্রণ স্থানান্তর করেন। সি তে সেটজ্যাম্প এবং লংজ্যাম্পের ব্যবহারিক ব্যবহার দেখুন ।

কি

  1. ইনডিকেটর
  2. কোড
  3. উদ্দেশ্য
  4. কলব্যাক

ইনডিকেটর

একটি ত্রুটি সূচক কেবল আপনাকে বলে যে একটি সমস্যা আছে তবে বলেন সমস্যার প্রকৃতি সম্পর্কে কিছুই নয়:

struct foo *f = foo_init();
if(!f) {
  /// handle the absence of foo
}

ত্রুটি পরিস্থিতি যোগাযোগের জন্য কোনও ফাংশনের পক্ষে এটি সর্বনিম্ন শক্তিশালী উপায়, তবে, যদি কলার কোনওভাবেই স্নাতকৃত পদ্ধতিতে ত্রুটির প্রতিক্রিয়া না জানায় তবে তা নিখুঁত।

কোড

একটি ত্রুটি কোড কলকারীকে সমস্যার প্রকৃতি সম্পর্কে জানায় এবং উপযুক্ত প্রতিক্রিয়ার জন্য অনুমতি দিতে পারে (উপরের দিক থেকে)। এটি রিটার্ন মান হতে পারে, বা ত্রুটির যুক্তির উপরে look_ma () উদাহরণের মতো হতে পারে।

উদ্দেশ্য

একটি ত্রুটিযুক্ত বস্তুর সাথে, কলকারীকে নির্বিচারে জটিল সমস্যা সম্পর্কে অবহিত করা যেতে পারে। উদাহরণস্বরূপ, একটি ত্রুটি কোড এবং একটি উপযুক্ত মানব পাঠযোগ্য বার্তা। এটি কলকারীকে আরও জানাতে পারে যে একাধিক জিনিস ভুল হয়েছে, বা কোনও সংগ্রহ প্রক্রিয়া করার সময় আইটেম প্রতি ত্রুটি:

struct collection friends;
enum error *e = malloc(c.size * sizeof(enum error));
...
ask_for_favor(friends, reason);
for(int i = 0; i < c.size; i++) {
   if(reason[i] == NOT_FOUND) find(friends[i]);
}

ত্রুটি অ্যারে প্রাক-বরাদ্দ পরিবর্তে, আপনি অবশ্যই (পুনরায়) অবশ্যই প্রয়োজন হিসাবে গতিশীল বরাদ্দ করতে পারেন।

কলব্যাক

ত্রুটিগুলি হ্যান্ডেল করার সবচেয়ে শক্তিশালী উপায় হ'ল কলব্যাক, কারণ কিছু ভুল হয়ে গেলে আপনি কী আচরণটি দেখতে চান তা ফাংশনটি বলতে পারেন। প্রতিটি ফাংশনে একটি কলব্যাক আর্গুমেন্ট যুক্ত করা যেতে পারে, বা যদি কাস্টমাইজেশন ইউআইএস কেবলমাত্র এর মতো স্ট্রাক্টের জন্য প্রয়োজন হয়:

 struct foo {
    ...
    void (error_handler)(char *);
 };

 void default_error_handler(char *message) { 
    assert(f);
    printf("%s", message);
 }

 void foo_set_error_handler(struct foo *f, void (*eh)(char *)) {
    assert(f);
    f->error_handler = eh;
 }

 struct foo *foo_init() {
    struct foo *f = malloc(sizeof(struct foo));
    foo_set_error_handler(f, default_error_handler);
    return f;
 }


 struct foo *f = foo_init();
 foo_something();

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

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


1

সম্পাদনা: আপনার যদি কেবলমাত্র শেষ ত্রুটির অ্যাক্সেসের প্রয়োজন হয় এবং আপনি মাল্টিথ্রেডেড পরিবেশে কাজ করেন না।

আপনি কেবল সত্য / মিথ্যা (অথবা আপনি সিতে কাজ করেন এবং বুল ভেরিয়েবলগুলি সমর্থন না করে যদি কিছু ধরণের # ডেফাইন) ফিরে আসতে পারেন, এবং একটি বিশ্বব্যাপী ত্রুটি বাফার রয়েছে যা শেষ ত্রুটিটি ধরে রাখবে:

int getObjectSize(MYAPIHandle h, int* returnedSize);
MYAPI_ERROR LastError;
MYAPI_ERROR* getLastError() {return LastError;};
#define FUNC_SUCCESS 1
#define FUNC_FAIL 0

if(getObjectSize(h, &size) != FUNC_SUCCESS ) {
    MYAPI_ERROR* error = getLastError();
    // error handling
}

প্রকৃতপক্ষে তবে এটি সি নয় এটি ওএস দ্বারা সরবরাহ করা হতে পারে বা না। আপনি যদি রিয়েল টাইম অপারেটিং সিস্টেমগুলিতে কাজ করছেন উদাহরণস্বরূপ আপনার এটি নাও রয়েছে।
ইলিয়া

1

দ্বিতীয় পদ্ধতির সাহায্যে সংকলকটি আরও অনুকূলিত কোড তৈরি করতে দেয়, কারণ যখন কোনও ভেরিয়েবলের ঠিকানা কোনও ফাংশনে প্রেরণ করা হয়, তখন সংকলক পরবর্তী ফাংশনগুলিতে কল করার সময় রেজিস্টার (গুলি) এর মান রাখতে পারে না। সমাপ্তির কোডটি সাধারণত একবার মাত্র কল করার পরে ব্যবহৃত হয়, যেখানে কল থেকে ফিরে আসা "আসল" ডেটা আরও প্রায়শই ব্যবহার করা যেতে পারে


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


1
ভাল কৌশল। আমি gotoবারবার এর পরিবর্তে 'গুলি' এর সাথে আরও নীচু দেখতে পাই if। তথ্যসূত্র: এক , দুই
এন্ট_222

0

অন্যান্য দুর্দান্ত উত্তরের পাশাপাশি, আমি আপনাকে পরামর্শ দিচ্ছি যে প্রতিটি কলটিতে একটি লাইন সংরক্ষণ করার জন্য আপনি ত্রুটি পতাকা এবং ত্রুটি কোড পৃথক করার চেষ্টা করুন, যেমন:

if( !doit(a, b, c, &errcode) )
{   (* handle *)
    (* thine  *)
    (* error  *)
}

আপনার যখন প্রচুর ত্রুটি-পরীক্ষা করা হয়, তখন এই সামান্য সরলীকরণটি সত্যই সহায়তা করে।

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