সি তে বক্তব্য ধরার চেষ্টা করুন


101

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


3
যখন স্ট্যাকটি অনাবৃত থাকে তখন স্বয়ংক্রিয়ভাবে সংস্থানগুলি মুক্ত করার প্রক্রিয়া ব্যতীত ব্যতিক্রমের মতো প্রক্রিয়াগুলি কার্যকর হবে না। সি ++ আরএআইআই ব্যবহার করে; জাভা, সি #, পাইথন ইত্যাদিতে আবর্জনা সংগ্রহকারীদের ব্যবহার। (। আর আবর্জনা সংগ্রাহক ওনলি মেমোরি স্বয়ংক্রিয়ভাবে সম্পদের বিনামূল্যে অন্যান্য ধরনের মুক্ত মনে রাখবেন যে, তারা কিছু finalizers বা প্রসঙ্গ পরিচালকদের মত যোগ ...)
jamesdlin

@ জামেসডলিন, আমরা কেন সি দিয়ে আরআইআই করতে পারিনি?
পেসেরিয়র

1
@ পেসারিয়ার আরআইআই-তে স্বয়ংক্রিয়ভাবে কলিং ফাংশন প্রয়োজন যখন বস্তুগুলি ধ্বংস হয়ে যায় (যেমন, ধ্বংসকারী)। আপনি কীভাবে সি তে এই প্রস্তাব করবেন?
জেমসডলিন

উত্তর:


90

সি নিজেই ব্যতিক্রমগুলি সমর্থন করে না তবে আপনি সেগুলি কল setjmpএবং longjmpকল সহ একটি ডিগ্রীতে সিমুলেট করতে পারেন ।

static jmp_buf s_jumpBuffer;

void Example() { 
  if (setjmp(s_jumpBuffer)) {
    // The longjmp was executed and returned control here
    printf("Exception happened here\n");
  } else {
    // Normal code execution starts here
    Test();
  }
}

void Test() {
  // Rough equivalent of `throw`
  longjmp(s_jumpBuffer, 42);
}

এই ওয়েবসাইটটিতে কীভাবে setjmpএবং এর সাথে ব্যতিক্রমগুলি অনুকরণ করা যায় তার একটি সুন্দর টিউটোরিয়াল রয়েছেlongjmp


1
দুর্দান্ত সমাধান! এই সমাধান কি ক্রস? এটি আমার জন্য এমএসভিসি ২০১২ তে কাজ করেছে তবে ম্যাকোএসএক্স ক্ল্যাং সংকলকটিতে নেই।
mannysz

1
আমাকে আঁকড়ে ধরুন: আমি ভেবেছিলাম যে ধরার চেষ্টা করার ফলে আপনি ব্যতিক্রমগুলি ধরতে পারবেন (যেমন শূন্য দ্বারা বিভাজন)। এই ফাংশনটি আপনাকে কেবল নিজেকে ছুঁড়ে ফেলা ব্যতিক্রমগুলি ধরতে দেয় বলে মনে হয়। লংজ্যাম্পকে ডেকে সত্যিকারের ব্যতিক্রম ছুঁড়ে দেওয়া হচ্ছে না? আমি যদি এই কোডটি এমন কিছু করতে ব্যবহার করি তবে try{ x = 7 / 0; } catch(divideByZeroException) {print('divided by zero')}; এটি ঠিক কাজ করবে না?
স্যাম

শূন্য দ্বারা ডিভাইড এমনকি সি ++ তেও ব্যতিক্রম নয়, এটি পরিচালনা করার জন্য আপনাকে ডিভায়ারটি শূন্য নয় এবং এটি পরিচালনা করতে হবে বা আপনি শূন্য সূত্র দ্বারা কোনও বিভাজন চালানোর সময় নিক্ষেপিত SIGFPE পরিচালনা করতে হবে।
জেমস

25

অনুরূপ ত্রুটি পরিচালনার পরিস্থিতিতে আপনি সি তে গোটো ব্যবহার করেন ।
এটি আপনি সিতে প্রাপ্ত ব্যতিক্রমগুলির নিকটতম সমতুল্য is


3
@ জেনসগাস্ট্ট এটি হ'ল যা বর্তমানে খুব প্রায়ই ব্যবহৃত হয় এবং উদাহরণস্বরূপ যেখানে এটি বোধগম্য হয় (সেটজ্যাম্প / এলজেএমপি আরও ভাল বিকল্প, তবে লেবেল + গোটো সাধারণত বেশি ব্যবহৃত হয়)।
টমাস প্রুজিনা

1
@ অওএও, সম্ভবত gotoত্রুটি পরিচালনার জন্য বেশি ব্যবহৃত হয়, তবে কী? প্রশ্নটি ত্রুটি পরিচালনার ক্ষেত্রে নয় তবে স্পষ্টভাবে চেষ্টা / ধরা সমতুল্য সম্পর্কে। gotoচেষ্টা / ধরার সমতুল্য নয় কারণ এটি একই ফাংশনে সীমাবদ্ধ।
জেনস গুস্ট্ট

@ জেনসগাস্ট্ট আমি গোটো এবং এটি ব্যবহারকারী লোকদের ঘৃণা / ভয়ের প্রতি প্রতিক্রিয়া জানালাম (আমার শিক্ষকরা আমাকে বিশ্ববিদ্যালয়েও গোটো ব্যবহারের ভীতিকর গল্প বলেছিলেন)। [ওটি] গোটো সম্পর্কে সত্যই সত্যই ঝুঁকিপূর্ণ এবং 'মেঘলা' জিনিসটি হ'ল 'পিছনের দিকে ফিরে', তবে আমি দেখেছি যে লিনাক্স ভিএফএসে (গিট দোষের লোকটি কসম খেয়েছিল যে এটি পারফরম্যান্সকে সমালোচনা-উপকারী)।
টমাস প্রুজিনা

একটি আধুনিক, প্রশস্ত-স্বীকৃত, পিয়ার পর্যালোচনা উত্স হিসাবে ব্যবহৃত চেষ্টা / ধরার পদ্ধতি হিসাবে বৈধ ব্যবহারের জন্য সিস্টেমটেক্টল উত্স দেখুন goto। অনুসন্ধান করুন gotoএকটি "থ্রো" সমতুল্য জন্য, এবং finishএকটি "ধরা" জন্য সমতুল্য।
স্টুয়ার্ট

13

ঠিক আছে, আমি এর জবাব দিতে পারিনি। আমাকে প্রথমে বলতে দাও যে এটি সি তে অনুকরণ করা ভাল ধারণা বলে আমি মনে করি না কারণ এটি সত্যিকার অর্থে সি এর জন্য একটি বিদেশী ধারণা is

আমরা পারি ব্যবহার প্রাক প্রসেসর এবং স্থানীয় স্ট্যাকের ভেরিয়েবল অপব্যবহার ব্যবহার সি ++ ব্যবহার করে দেখুন / থ্রো / ধরা একটি সীমিত সংস্করণ দিতে।

সংস্করণ 1 (স্থানীয় স্কোপ নিক্ষেপ)

#include <stdbool.h>

#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) __HadError=true;goto ExitJmp;

সংস্করণ 1 কেবল স্থানীয় থ্রো (ফাংশনের সুযোগটি ছেড়ে যেতে পারে না)। কোডে ভেরিয়েবল ঘোষণার সি 99 এর ক্ষমতার উপর এটি নির্ভর করে না (যদি চেষ্টাটি প্রথম কাজটিতে হয় তবে এটি সি 89 এ কাজ করা উচিত)।

এই ফাংশনটি কেবল একটি স্থানীয় ভেরি তৈরি করে তাই এটি কোনও ত্রুটি ছিল কিনা তা জানতে পারে এবং ক্যাচ ব্লকে ঝাঁপ দেওয়ার জন্য একটি গোটো ব্যবহার করে।

উদাহরণ স্বরূপ:

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

#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) __HadError=true;goto ExitJmp;

int main(void)
{
    try
    {
        printf("One\n");
        throw();
        printf("Two\n");
    }
    catch(...)
    {
        printf("Error\n");
    }
    return 0;
}

এটি এর মতো কিছু কাজ করে:

int main(void)
{
    bool HadError=false;
    {
        printf("One\n");
        HadError=true;
        goto ExitJmp;
        printf("Two\n");
    }
ExitJmp:
    if(HadError)
    {
        printf("Error\n");
    }
    return 0;
}

সংস্করণ 2 (স্কোপ জাম্পিং)

#include <stdbool.h>
#include <setjmp.h>

jmp_buf *g__ActiveBuf;

#define try jmp_buf __LocalJmpBuff;jmp_buf *__OldActiveBuf=g__ActiveBuf;bool __WasThrown=false;g__ActiveBuf=&__LocalJmpBuff;if(setjmp(__LocalJmpBuff)){__WasThrown=true;}else
#define catch(x) g__ActiveBuf=__OldActiveBuf;if(__WasThrown)
#define throw(x) longjmp(*g__ActiveBuf,1);

সংস্করণ 2 অনেক বেশি জটিল তবে মূলত একইভাবে কাজ করে। এটি চেষ্টা ব্লকটিতে বর্তমান ফাংশনটির বাইরে একটি দীর্ঘ জাম্প ব্যবহার করে। চেষ্টা ব্লকটি কোড ব্লকটি ক্যাচ ব্লকে এড়িয়ে যাওয়ার জন্য একটি if / অন্যটি ব্যবহার করে যা স্থানীয় ভেরিয়েবলটি এটি ধরতে পারে কিনা তা পরীক্ষা করে।

উদাহরণটি আবার প্রসারিত হয়েছে:

jmp_buf *g_ActiveBuf;

int main(void)
{
    jmp_buf LocalJmpBuff;
    jmp_buf *OldActiveBuf=g_ActiveBuf;
    bool WasThrown=false;
    g_ActiveBuf=&LocalJmpBuff;

    if(setjmp(LocalJmpBuff))
    {
        WasThrown=true;
    }
    else
    {
        printf("One\n");
        longjmp(*g_ActiveBuf,1);
        printf("Two\n");
    }
    g_ActiveBuf=OldActiveBuf;
    if(WasThrown)
    {
        printf("Error\n");
    }
    return 0;
}

এটি বিশ্বব্যাপী পয়েন্টার ব্যবহার করে তাই লংজ্যাম্প () জানে যে শেষ চেষ্টাটি কী হয়েছিল। আমরা স্ট্যাকটি আপত্তিজনক ব্যবহার করছি যাতে চাইল্ড ফাংশনগুলিতেও চেষ্টা / ধরা ব্লক থাকতে পারে।

এই কোডটি ব্যবহারের কয়েকটি নিচের দিক রয়েছে (তবে এটি একটি মজাদার মানসিক অনুশীলন):

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

চমৎকার বিকল্প সমাধান।
হাসিব মীর 17'18

সংস্করণ 1 দুর্দান্ত ধারণা, তবে __HadError পরিবর্তনশীল পুনরায় সেট করা বা স্কোপ করা প্রয়োজন। অন্যথায় আপনি একই ব্লকে একাধিক চেষ্টা-ব্যবহার করতে পারবেন না be যেমন একটি গ্লোবাল ফাংশন ব্যবহার করুন bool __ErrorCheck(bool &e){bool _e = e;e=false;return _e;}। তবে স্থানীয় ভেরিয়েবলটিও নতুনভাবে সংজ্ঞায়িত হবে, তাই জিনিসগুলি হাত থেকে সামান্য বেরিয়ে আসে।
flamewave000

হ্যাঁ, এটি একই ফাংশনে একটি চেষ্টা করার মধ্যে সীমাবদ্ধ। ভেরিয়েবলের একটি বড় সমস্যা তবে লেবেল হিসাবে আপনার একই ফাংশনে সদৃশ লেবেল থাকতে পারে না।
পল হাচিনসন

10

সি 99 এ, আপনি স্থানীয় ব্যবহারের নিয়ন্ত্রণ প্রবাহের জন্য setjmp/ ব্যবহার করতে পারেন longjmp

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


5

অন্যান্য উত্তর কয়েকটি ব্যবহার সহজ মামলা ঢেকে যদিও setjmpএবং longjmp, একটি বাস্তব অ্যাপ্লিকেশনে সেখানে যে সত্যিই ব্যাপার দুই উদ্বেগ আছে।

  1. চেষ্টা / ব্লক ব্লক নেস্টিং। আপনার jmp_bufইচ্ছার জন্য একটি একক গ্লোবাল ভেরিয়েবল ব্যবহার করা এগুলি কার্যকর করে না।
  2. থ্রেডিং। আপনার জন্য একটি একক বৈশ্বিক পরিবর্তনশীল jmp_bufএই পরিস্থিতিতে সমস্ত ধরণের ব্যথা ঘটাবে।

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

সুতরাং এর পরিবর্তে (জ্যারেডপারের দুর্দান্ত উত্তর থেকে)

static jmp_buf s_jumpBuffer;

void Example() { 
  if (setjmp(s_jumpBuffer)) {
    // The longjmp was executed and returned control here
    printf("Exception happened\n");
  } else {
    // Normal code execution starts here
    Test();
  }
}

void Test() {
  // Rough equivalent of `throw`
  longjump(s_jumpBuffer, 42);
}

আপনি এর মতো কিছু ব্যবহার করবেন:

#define MAX_EXCEPTION_DEPTH 10;
struct exception_state {
  jmp_buf s_jumpBuffer[MAX_EXCEPTION_DEPTH];
  int current_depth;
};

int try_point(struct exception_state * state) {
  if(current_depth==MAX_EXCEPTION_DEPTH) {
     abort();
  }
  int ok = setjmp(state->jumpBuffer[state->current_depth]);
  if(ok) {
    state->current_depth++;
  } else {
    //We've had an exception update the stack.
    state->current_depth--;
  }
  return ok;
}

void throw_exception(struct exception_state * state) {
  longjump(state->current_depth-1,1);
}

void catch_point(struct exception_state * state) {
    state->current_depth--;
}

void end_try_point(struct exception_state * state) {
    state->current_depth--;
}

__thread struct exception_state g_exception_state; 

void Example() { 
  if (try_point(&g_exception_state)) {
    catch_point(&g_exception_state);
    printf("Exception happened\n");
  } else {
    // Normal code execution starts here
    Test();
    end_try_point(&g_exception_state);
  }
}

void Test() {
  // Rough equivalent of `throw`
  throw_exception(g_exception_state);
}

আবার এর আরও বাস্তব সংস্করণে ত্রুটি সম্পর্কিত তথ্য সংরক্ষণের কিছু উপায় অন্তর্ভুক্ত থাকবে exception_state, আরও ভাল পরিচালনা করাMAX_EXCEPTION_DEPTH (সম্ভবত বাফার বাড়ানোর জন্য রিলোক ব্যবহার করা, বা এর মতো কিছু)।

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


4

একটি দ্রুত Google অনুসন্ধান উৎপাদনের যেমন সমাধান kludgey এই অন্যদের উল্লেখ করেছি যে ব্যবহার setjmp / longjmp। সি ++ / জাভার চেষ্টা / ক্যাচের মতো সোজা এবং মার্জিত কিছুই নয়। আমি নিজেই নিজেকে সামলানোর অ্যাডা ব্যতিক্রমের পক্ষে আংশিক।

বিবৃতি দিয়ে সবকিছু চেক করুন :)


4

এটি setjmp/longjmpসি এর সাথে করা যেতে পারে P99 এর জন্য বেশ আরামদায়ক একটি টুলসেট রয়েছে যা সি 11 এর নতুন থ্রেড মডেলের সাথে সামঞ্জস্যপূর্ণ।


2

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

GameEngine *CreateGameEngine(GameEngineParams const *params)
{
    /* Declare an error handler variable. This will hold the address
       to jump to if an error occurs to cleanup pending resources.
       Initialize it to the err label which simply returns an
       error value (NULL in this example). The && operator resolves to
       the address of the label err */
    void *eh = &&err;

    /* Try the allocation */
    GameEngine *engine = malloc(sizeof *engine);
    if (!engine)
        goto *eh; /* this is essentially your "throw" */

    /* Now make sure that if we throw from this point on, the memory
       gets deallocated. As a convention you could name the label "undo_"
       followed by the operation to rollback. */
    eh = &&undo_malloc;

    /* Now carry on with the initialization. */
    engine->window = OpenWindow(...);
    if (!engine->window)
        goto *eh;   /* The neat trick about using approach is that you don't
                       need to remember what "undo" label to go to in code.
                       Simply go to *eh. */

    eh = &&undo_window_open;

    /* etc */

    /* Everything went well, just return the device. */
    return device;

    /* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}

আপনি যদি চান, আপনি কার্যকরভাবে আপনার নিজের ত্রুটি-পরিচালনা ব্যবস্থা প্রয়োগ করে সংজ্ঞায়িত সাধারণ কোডটি রিফ্যাক্টর করতে পারেন।

/* Put at the beginning of a function that may fail. */
#define declthrows void *_eh = &&err

/* Cleans up resources and returns error result. */
#define throw goto *_eh

/* Sets a new undo checkpoint. */
#define undo(label) _eh = &&undo_##label

/* Throws if [condition] evaluates to false. */
#define check(condition) if (!(condition)) throw

/* Throws if [condition] evaluates to false. Then sets a new undo checkpoint. */
#define checkpoint(label, condition) { check(condition); undo(label); }

তারপরে উদাহরণ হয়ে যায়

GameEngine *CreateGameEngine(GameEngineParams const *params)
{
    declthrows;

    /* Try the allocation */
    GameEngine *engine = malloc(sizeof *engine);
    checkpoint(malloc, engine);

    /* Now carry on with the initialization. */
    engine->window = OpenWindow(...);
    checkpoint(window_open, engine->window);

    /* etc */

    /* Everything went well, just return the device. */
    return device;

    /* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}

2

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

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    unsigned int  id;
    char         *name;
    char         *msg;
} error;

#define _printerr(e, s, ...) fprintf(stderr, "\033[1m\033[37m" "%s:%d: " "\033[1m\033[31m" e ":" "\033[1m\033[37m" " ‘%s_error’ " "\033[0m" s "\n", __FILE__, __LINE__, (*__err)->name, ##__VA_ARGS__)
#define printerr(s, ...) _printerr("error", s, ##__VA_ARGS__)
#define printuncaughterr() _printerr("uncaught error", "%s", (*__err)->msg)

#define _errordef(n, _id) \
error* new_##n##_error_msg(char* msg) { \
    error* self = malloc(sizeof(error)); \
    self->id = _id; \
    self->name = #n; \
    self->msg = msg; \
    return self; \
} \
error* new_##n##_error() { return new_##n##_error_msg(""); }

#define errordef(n) _errordef(n, __COUNTER__ +1)

#define try(try_block, err, err_name, catch_block) { \
    error * err_name = NULL; \
    error ** __err = & err_name; \
    void __try_fn() try_block \
    __try_fn(); \
    void __catch_fn() { \
        if (err_name == NULL) return; \
        unsigned int __##err_name##_id = new_##err##_error()->id; \
        if (__##err_name##_id != 0 && __##err_name##_id != err_name->id) \
            printuncaughterr(); \
        else if (__##err_name##_id != 0 || __##err_name##_id != err_name->id) \
            catch_block \
    } \
    __catch_fn(); \
}

#define throw(e) { *__err = e; return; }

_errordef(any, 0)

ব্যবহার:

errordef(my_err1)
errordef(my_err2)

try ({
    printf("Helloo\n");
    throw(new_my_err1_error_msg("hiiiii!"));
    printf("This will not be printed!\n");
}, /*catch*/ any, e, {
    printf("My lovely error: %s %s\n", e->name, e->msg);
})

printf("\n");

try ({
    printf("Helloo\n");
    throw(new_my_err2_error_msg("my msg!"));
    printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
    printerr("%s", e->msg);
})

printf("\n");

try ({
    printf("Helloo\n");
    throw(new_my_err1_error());
    printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
    printf("Catch %s if you can!\n", e->name);
})

আউটপুট:

Helloo
My lovely error: my_err1 hiiiii!

Helloo
/home/naheel/Desktop/aa.c:28: error: my_err2_error my msg!

Helloo
/home/naheel/Desktop/aa.c:38: uncaught error: my_err1_error 

মনে রাখবেন যে এটি নেস্টেড ফাংশনগুলি এবং ব্যবহার করছে __COUNTER__। আপনি যদি সিসি ব্যবহার করছেন তবে আপনি নিরাপদে থাকবেন।


1

পুনরায় চেষ্টা করুন / ধরার অনুকরণ করতে গোটো ব্যবহার করুন, IMHO এটি খুব পরিষ্কার এবং মার্জিত:

/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success. */
int rdbSave(char *filename) {
    char tmpfile[256];
    FILE *fp;
    rio rdb;
    int error = 0;

    snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
    fp = fopen(tmpfile,"w");
    if (!fp) {
        redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
            strerror(errno));
        return REDIS_ERR;
    }

    rioInitWithFile(&rdb,fp);
    if (rdbSaveRio(&rdb,&error) == REDIS_ERR) {
        errno = error;
        goto werr;
    }

    /* Make sure data will not remain on the OS's output buffers */
    if (fflush(fp) == EOF) goto werr;
    if (fsync(fileno(fp)) == -1) goto werr;
    if (fclose(fp) == EOF) goto werr;

    /* Use RENAME to make sure the DB file is changed atomically only
     * if the generate DB file is ok. */
    if (rename(tmpfile,filename) == -1) {
        redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
        unlink(tmpfile);
        return REDIS_ERR;
    }
    redisLog(REDIS_NOTICE,"DB saved on disk");
    server.dirty = 0;
    server.lastsave = time(NULL);
    server.lastbgsave_status = REDIS_OK;
    return REDIS_OK;

werr:
    fclose(fp);
    unlink(tmpfile);
    redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
    return REDIS_ERR;
}

কোডটি নষ্ট হয়ে গেছে। errnoব্যর্থ সিস্টেম কলের পরে কেবল তিনটি কল নয় কেবল ব্যবহার করা উচিত।
ceving

এই কোডটি একাধিক জায়গায় ত্রুটি পরিচালনা করার ত্রুটির সদৃশ করে এবং একাধিকবার fclose (fp) কল করার মতো ভুল কাজগুলি করতে পারে। একাধিক লেবেল ব্যবহার করা এবং সেই সমস্ত লেবেলগুলি (সমস্ত ত্রুটির জন্য কেবল একটির চেয়ে বরং) পুনরুদ্ধার করার দরকার আছে এমনটি এনকোড করা আরও ভাল হবে এবং কোডটিতে কোথায় ত্রুটি ঘটেছিল তার উপর নির্ভর করে সঠিক ত্রুটি পরিচালনার স্পটে প্রবেশ করতে হবে।
jschultz410

1

সি তে, আপনি যদি স্পষ্টত ত্রুটি পরিচালনার জন্য + গেটো এর ম্যানুয়াল ব্যবহারের মাধ্যমে স্বয়ংক্রিয় "অবজেক্ট পুনঃনির্মাণ" ব্যতিক্রমগুলি "সিমুলেট" করতে পারেন।

আমি প্রায়শই নীচের মতো সি কোডটি লিখি (ত্রুটি পরিচালনার হাইলাইট করতে সিদ্ধ হয়ে):

#include <assert.h>

typedef int errcode;

errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
    errcode ret = 0;

    if ( ( ret = foo_init( f ) ) )
        goto FAIL;

    if ( ( ret = goo_init( g ) ) )
        goto FAIL_F;

    if ( ( ret = poo_init( p ) ) )
        goto FAIL_G;

    if ( ( ret = loo_init( l ) ) )
        goto FAIL_P;

    assert( 0 == ret );
    goto END;

    /* error handling and return */

    /* Note that we finalize in opposite order of initialization because we are unwinding a *STACK* of initialized objects */

FAIL_P:
    poo_fini( p );

FAIL_G:
    goo_fini( g );

FAIL_F:
    foo_fini( f );

FAIL:
    assert( 0 != ret );

END:
    return ret;        
}

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

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

#include <assert.h>
#include <stdio.h>
#include <string.h>

#define TRY( X, LABEL ) do { if ( ( X ) ) { fprintf( stderr, "%s:%d: Statement '" #X "' failed! %d, %s\n", __FILE__, __LINE__, ret, strerror( ret ) ); goto LABEL; } while ( 0 )

typedef int errcode;

errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
    errcode ret = 0;

    TRY( ret = foo_init( f ), FAIL );
    TRY( ret = goo_init( g ), FAIL_F );
    TRY( ret = poo_init( p ), FAIL_G );
    TRY( ret = loo_init( l ), FAIL_P );

    assert( 0 == ret );
    goto END;

    /* error handling and return */

FAIL_P:
    poo_fini( p );

FAIL_G:
    goo_fini( g );

FAIL_F:
    foo_fini( f );

FAIL:
    assert( 0 != ret );

END:
    return ret;        
}

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

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

পদ্ধতিগতভাবে এইভাবে কোডিং (যেমন - একক এন্ট্রি এবং একক প্রস্থান পয়েন্ট সহ) প্রাক এবং পোস্ট ("শেষ অবধি") যুক্তি সন্নিবেশ করা খুব সহজ করে তোলে যা নির্বিশেষে যাই হোক না কেন। আপনি মাত্র "লেবেলটি" শেষের লেবেলের পরে রেখেছেন put


1
খুব সুন্দর. আমি অনুরূপ কিছু করতে ঝোঁক। গোটো এই দৃশ্যের জন্য দুর্দান্ত। পার্থক্যটি হ'ল আমি শেষ "গোটো এন্ডে" এর প্রয়োজনীয়তাটি দেখতে পাচ্ছি না, আমি কেবলমাত্র সেই পর্যায়ে একটি সাফল্য রিটার্ন সন্নিবেশ করলাম, বিশ্রামের পরে একটি ব্যর্থ প্রত্যাবর্তন।
নিল রায়

1
ধন্যবাদ @ নীলরয় গোটো শেষ হওয়ার কারণটি হ'ল আমি আমার ফাংশনের সিংহভাগই পছন্দ করি যে একটি একক প্রবেশ পয়েন্ট এবং একক বহির্গমন পয়েন্ট। এইভাবে যদি আমি কোনও ফাংশনে কিছুটা "অবশেষে" যুক্তি যুক্ত করতে চাই তবে আমি চিন্তার প্রয়োজন ছাড়াই সবসময় সহজেই করতে পারি অন্য কোথাও লুকিয়ে থাকা আরও কিছু লুকানো রিটার্ন রয়েছে। :)
jschultz410

0

আপনি উইন 32 এর সাথে সি ব্যবহার করছেন, আপনি চেষ্টা / ধরনের সিমুলেট করার জন্য এর স্ট্রাকচার্ড এক্সসেপশন হ্যান্ডলিং (এসইএইচ) উপার্জন করতে পারেন ।

আপনি যদি প্ল্যাটফর্মগুলিতে সি ব্যবহার করছেন যা সমর্থন করে না setjmp()এবং longjmp(), pjsip লাইব্রেরির এই ব্যতিক্রম হ্যান্ডলিংটি একবার দেখুন , এটি তার নিজস্ব বাস্তবায়ন সরবরাহ করে


-1

সম্ভবত কোনও প্রধান ভাষা নয় (দুর্ভাগ্যবশত), তবে এপিএলে ⎕EA অপারেশন রয়েছে (এক্সিকিউট অলটারনেটের পক্ষে দাঁড়ানো)।

ব্যবহার: 'Y' ⎕EA 'X' যেখানে X এবং Y হয় স্ট্রিং বা ফাংশনের নাম হিসাবে সরবরাহিত কোড স্নিপেট।

যদি এক্স কোনও ত্রুটিতে চলে যায় তবে এর পরিবর্তে ওয়াই (সাধারণত ত্রুটি-পরিচালনা) কার্যকর করা হবে।


2
হাই ম্যাপো, স্ট্যাকওভারফ্লোতে আপনাকে স্বাগতম। আকর্ষণীয় হলেও প্রশ্নটি সিটিতে এটি করার বিষয়ে ছিল specifically সুতরাং এটি সত্যই প্রশ্নের উত্তর
লুসার droog
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.