সি তে সেটজ্যাম্প এবং লংজ্যাম্পের ব্যবহারিক ব্যবহার


99

এম্বেডড প্রোগ্রামিংয়ে বাস্তব setjmp()এবং longjmp()কার্যকারিতা ব্যবহারিকভাবে কোথায় ব্যবহার করা যেতে পারে সে সম্পর্কে কেউ আমাকে ব্যাখ্যা করতে পারেন? আমি জানি যে এগুলি ত্রুটি পরিচালনার জন্য। তবে আমি কিছু ব্যবহারের ক্ষেত্রে জানতে চাই।


অন্য কোনও প্রোগ্রামিংয়ের মতো ত্রুটি পরিচালনা করার জন্য। আমি ব্যবহারের পার্থক্য দেখছি না ???
টনি দ্য লায়ন


গতির জন্য? হ্যাঁ. কারণ ক) এটি একটি লুপের চেয়ে ধীর গতিতে চলে এবং খ) কারণ এটি সহজেই অনুকূলিত করা যায় না (যেমন বিলম্ব মোছার মতো, বা দুটি)। সুতরাং সেটজ্যাম্প এবং লংজ্যাম্প স্পষ্টভাবে শাসন করুন!
দ্য ব্লাস্টঅন

প্রদত্ত উত্তরগুলির চেয়ে অন্য উত্তরটি হ'ল এখানে স্ট্যাকওভারফ্লো.com/ প্রশ্নস / 3৩৩45৫৫৫/২ আপনি longjmp()সিগন্যাল হ্যান্ডলার থেকে বেরিয়ে আসতে ব্যবহার করতে পারেন , বিশেষত এর মতো জিনিস BUS ERROR। এই সংকেতটি সাধারণত পুনরায় আরম্ভ করতে পারে না। একটি এম্বেড অ্যাপ্লিকেশন সুরক্ষা এবং শক্তিশালী অপারেশনের জন্য এই কেসটি পরিচালনা করতে পারে wish
নির্দ্বিধ শব্দ

এবং setjmpবিএসডি এবং লিনাক্সের পারফরম্যান্স পার্থক্য সম্পর্কে , "টাইমিং সেটজ্যাম্প এবং স্ট্যান্ডার্ডস অফ জয়" দেখুন , যা ব্যবহারের পরামর্শ দেয় sigsetjmp
আইওনিস ফিলিপিসিস

উত্তর:


85

ত্রুটি পরিচালনার ক্ষেত্রে
ধরুন অন্য অনেক ফাংশনে বাসা বাঁধার কোনও ফাংশনে গভীরভাবে ত্রুটি রয়েছে এবং ত্রুটি পরিচালনার বিষয়টি কেবল শীর্ষ স্তরের ফাংশনেই বোধগম্য হয়।

এটি খুব ক্লান্তিকর এবং উদ্বেগজনক হবে যদি এর মধ্যে সমস্ত ফাংশনগুলি স্বাভাবিকভাবে ফিরে আসে এবং রিটার্ন মানগুলি বা বিশ্বব্যাপী ত্রুটি ভেরিয়েবলের মূল্যায়ন করতে হয় যাতে নির্ধারণ করা হয় যে আরও প্রক্রিয়াকরণটি বোধগম্য নয় বা এমনকি খারাপও হবে।

এটি এমন একটি পরিস্থিতি যেখানে সেটজ্যাম্প / লংজ্যাম্পটি বোঝায়। এই পরিস্থিতিগুলি পরিস্থিতিগুলির মতো যেখানে অন্যান্য ল্যাঙ্গেজ (সি ++, জাভা) ব্যতিক্রম বোঝায় sense


ত্রুটি পরিচালনার পাশাপাশি কর্টিনগুলি , আমি অন্য একটি পরিস্থিতি সম্পর্কেও ভাবতে পারি যেখানে আপনার সিতে সেটজ্যাম্প / লংজ্যাম্প প্রয়োজন:

আপনার যখন কর্টিনগুলি প্রয়োগ করা দরকার তখন এটিই ঘটে ।

এখানে একটি সামান্য ডেমো উদাহরণ। আমি আশা করি এটি কিছু উদাহরণ কোডের জন্য শিবপ্রসাদ পলাশের অনুরোধটি সন্তুষ্ট করেছে এবং TheBlastOne এর প্রশ্নের জবাব দেয় যে কীভাবে setjmp / Longjmp কর্রোটিনগুলি প্রয়োগের পক্ষে সমর্থন করে (যতটা দেখছি এটি কোনও মানহীন বা নতুন আচরণের ভিত্তিতে নয়)।

সম্পাদনা করুন:
এটা হতে পারে যে এটা আসলে হয় একটি করতে অনির্ধারিত আচরণ longjmp নিচে (MikeMB মন্তব্য দেখুন; যদিও আমি এখনো যে যাচাই করতে সুযোগ ছিল না) callstack।

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

jmp_buf bufferA, bufferB;

void routineB(); // forward declaration 

void routineA()
{
    int r ;

    printf("(A1)\n");

    r = setjmp(bufferA);
    if (r == 0) routineB();

    printf("(A2) r=%d\n",r);

    r = setjmp(bufferA);
    if (r == 0) longjmp(bufferB, 20001);

    printf("(A3) r=%d\n",r);

    r = setjmp(bufferA);
    if (r == 0) longjmp(bufferB, 20002);

    printf("(A4) r=%d\n",r);
}

void routineB()
{
    int r;

    printf("(B1)\n");

    r = setjmp(bufferB);
    if (r == 0) longjmp(bufferA, 10001);

    printf("(B2) r=%d\n", r);

    r = setjmp(bufferB);
    if (r == 0) longjmp(bufferA, 10002);

    printf("(B3) r=%d\n", r);

    r = setjmp(bufferB);
    if (r == 0) longjmp(bufferA, 10003);
}


int main(int argc, char **argv) 
{
    routineA();
    return 0;
}

নিম্নলিখিত চিত্রটি কার্যকর করার প্রবাহটি দেখায়:
মৃত্যুদন্ড কার্যকর

সতর্কতা নোট
সেটজ্যাম্প / লংজ্যাম্প ব্যবহার করার সময় সচেতন হন যে স্থানীয় ভেরিয়েবলগুলির বৈধতার উপর তাদের প্রভাব রয়েছে যা প্রায়শই বিবেচনা করা হয় না।
সিএফ। এই বিষয় সম্পর্কে আমার প্রশ্ন


4
যেহেতু সেটজ্যাম্প প্রস্তুত করে, এবং লংজ্যাম্প বর্তমান কল স্কোপটি জাম্প স্কোপ থেকে ফিরে সেটজ্যাম্প স্কোপ থেকে কার্যকর করে, কীভাবে এটি কর্টিনগুলি প্রয়োগের সমর্থন করবে? আমি দেখতে পাচ্ছি না যে কীভাবে দীর্ঘস্থায়ীভাবে কাজ করা চালিয়ে যাওয়া রুটিনটি কার্যকর করা যেতে পারে।
দ্য ব্লাস্টঅন

4
@ দ্য ব্লাস্টওন উইকিপিডিয়া নিবন্ধটি দেখুন । আপনি setjmpআগে থাকলে আপনি ফাঁসি চালিয়ে যেতে পারেন longjmp। এটা মানহীন।
পোটোসওয়টার

11
কার্টাইনগুলি পৃথক স্ট্যাকের উপর চালানো দরকার, আপনার উদাহরণে যেমন দেখানো হয়েছে তেমন নয়। একই স্ট্যাক হিসাবে routineAএবং এটি routineBব্যবহার করে, এটি কেবল খুব আদিম করোটিনগুলির জন্য কাজ করে। প্রথম কল করার পরে যদি routineAকোনও গভীরভাবে নেস্ট routineCকরা কল হয় routineBএবং এটি কর্টিন হিসাবে routineCচলে routineB, তবে routineBতার রিটার্ন স্ট্যাক (কেবল স্থানীয় ভেরিয়েবলগুলিই নয়) ধ্বংস করতে পারে routineC। সুতরাং কোনও এক্সক্লুসিভ স্ট্যাক বরাদ্দ না করে ( alloca()কল করার পরে rountineB?) যদি রেসিপি হিসাবে ব্যবহার করা হয় তবে আপনি এই উদাহরণটি সহ গুরুতর সমস্যায় পড়বেন।
টিনো 19

7
দয়া করে আপনার উত্তরে উল্লেখ করুন যে কলস্ট্যাকের নিচে ঝাঁপিয়ে পড়া (এ থেকে বি) অবধারিত আচরণ।
মাইকএমবি

4
এটি প্রকৃতপক্ষে সংজ্ঞায়িত।
কৌতূহল

19

তত্ত্বটি হ'ল আপনি এগুলি ত্রুটি পরিচালনার জন্য ব্যবহার করতে পারেন যাতে আপনি চেইনের প্রতিটি কার্যক্রমে ত্রুটিগুলি পরিচালনা করার প্রয়োজন ছাড়াই গভীরভাবে নেস্টেড কল চেইন থেকে ঝাঁপিয়ে পড়তে পারেন।

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

বেশিরভাগ ক্ষেত্রে আমার অভিজ্ঞতায় যখনই আপনি ভাবেন যে setjmp/ ব্যবহার করে longjmpকাজ করবে, আপনার প্রোগ্রামটি পরিষ্কার এবং সহজ যে কল চেইনে প্রতিটি মধ্যবর্তী ফাংশন কল ত্রুটি পরিচালনা করতে পারে, বা এটি এতটা অগোছালো এবং অসম্ভব যে এটি করার সময় আপনার কী করা উচিত exit? ত্রুটি সম্মুখীন।


4
দয়া করে দেখুন libjpeg। সি ++ এর মতো, সি রুটিনগুলির বেশিরভাগ সংগ্রহগুলি struct *কোনও যৌথ হিসাবে কোনও কিছুতে পরিচালনা করতে এক সময় নেয়। স্থানীয় হিসাবে আপনার মধ্যবর্তী ফাংশন মেমরি বরাদ্দ সংরক্ষণের পরিবর্তে সেগুলি কাঠামোর মধ্যে সংরক্ষণ করা যেতে পারে। এটি কোনও longjmp()হ্যান্ডলারের মেমরি মুক্ত করতে দেয় । এছাড়াও, এর মধ্যে এতগুলি ব্লাস্টেড ব্যতিক্রম টেবিল নেই যা সমস্ত সি ++ সংকলক এখনও সত্যের 20 বছর পরে উত্পন্ন করে।
নির্দোষ শব্দ

Like every clever theory this falls apart when meeting reality.প্রকৃতপক্ষে, অস্থায়ী বরাদ্দ এবং এর মতো longjmp()কৌশলগুলি জটিল করে তোলা, যেহেতু আপনাকে setjmp()কল স্ট্যাকের একাধিকবার করতে হবে (প্রতিটি ক্রিয়াকলাপের জন্য একবার এটি বেরোনোর ​​আগে কিছু ধরণের পরিচ্ছন্নতার প্রয়োজন হয়, যার পরে "ব্যতিক্রমটি পুনরায় উত্থাপন" প্রয়োজন দ্বারা longjmp()প্রসঙ্গ ing এটি প্রাথমিকভাবে পেয়েছে যে)। এটিগুলির পরে যদি সেই সংস্থানগুলি সংশোধন করা হয় তবে এটি আরও খারাপ হবে setjmp(), যেহেতু এগুলি ক্লোবারিংয়ের হাত থেকে volatileরোধ করার জন্য আপনাকে তাদের ঘোষণা longjmp()করতে হবে।
সেভকো

10

সমন্বয় setjmpএবং longjmp"সুপার শক্তি goto"। অতিরিক্ত যত্ন সহ ব্যবহার করুন। যাইহোক, অন্যরা যেমন ব্যাখ্যা করেছেন যে, 18 টি ফাংশনের স্তরের জন্য একটি ত্রুটি বার্তা ফিরে পেতে চেয়ে longjmpআপনি get me back to the beginningদ্রুত করতে চাইলে, একটি খারাপ ত্রুটি পরিস্থিতি থেকে বেরিয়ে আসার জন্য খুব দরকারী ।

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

আমি খুব বেসিক থ্রেডিং প্রক্রিয়া সরবরাহ করতে দেখে setjmp/ longjmpব্যবহার করেছি used তবে এটি বেশ বিশেষ ক্ষেত্রে - এবং "স্ট্যান্ডার্ড" থ্রেডগুলি কীভাবে কাজ করে তা অবশ্যই নয়।

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

struct 
{
    void (*destructor)(void *ptr);
};


void LockForceUnlock(void *vlock)
{
   LOCK* lock = vlock;
}


LOCK func_lock;


void func()
{
   ref = add_destructor(LockForceUnlock, mylock);
   Lock(func_lock)
   ... 
   func2();   // May call longjmp. 

   Unlock(func_lock);
   remove_destructor(ref);
}

এই সিস্টেমের সাহায্যে আপনি "সি ++ এর মতো সম্পূর্ণ ব্যতিক্রম হ্যান্ডলিং" করতে পারেন। তবে এটি বেশ অগোছালো, এবং কোডটি ভালভাবে লেখা হচ্ছে তার উপর নির্ভর করে।


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

8

যেহেতু আপনি এম্বেডের কথা উল্লেখ করেছেন তাই আমি মনে করি এটি একটি অ-ব্যবহারের ক্ষেত্রে লক্ষ্য করা ভাল : যখন আপনার কোডিং স্ট্যান্ডার্ড এটিকে নিষিদ্ধ করে। উদাহরণস্বরূপ মিস্রা (মিস্রা-সি: 2004: বিধি 20.7) এবং জেএফএস (এভি বিধি 20): "সেটজ্যাম্প ম্যাক্রো এবং লংজ্যাম্প ফাংশন ব্যবহার করা হবে না।"


8

setjmpএবং longjmpইউনিট পরীক্ষায় খুব কার্যকর হতে পারে।

ধরুন আমরা নিম্নলিখিত মডিউলটি পরীক্ষা করতে চাই:

#include <stdlib.h>

int my_div(int x, int y)
{
    if (y==0) exit(2);
    return x/y;
}

সাধারণত, যদি পরীক্ষার জন্য ফাংশনটি অন্য ফাংশনকে কল করে, আপনি কল করার জন্য এটির জন্য একটি স্টাব ফাংশন ঘোষণা করতে পারেন যা নির্দিষ্ট প্রবাহকে পরীক্ষা করতে প্রকৃত ফাংশনটি কী করে তা নকল করে। এই ক্ষেত্রে যাইহোক, ফাংশন কল exitযা ফিরে না। স্টাবকে কোনওভাবে এই আচরণটি অনুকরণ করা দরকার। setjmpএবং longjmpএটি আপনার জন্য করতে পারেন।

এই ফাংশনটি পরীক্ষা করতে, আমরা নিম্নলিখিত পরীক্ষার প্রোগ্রামটি তৈরি করতে পারি:

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

// redefine assert to set a boolean flag
#ifdef assert
#undef assert
#endif
#define assert(x) (rslt = rslt && (x))

// the function to test
int my_div(int x, int y);

// main result return code used by redefined assert
static int rslt;

// variables controling stub functions
static int expected_code;
static int should_exit;
static jmp_buf jump_env;

// test suite main variables
static int done;
static int num_tests;
static int tests_passed;

//  utility function
void TestStart(char *name)
{
    num_tests++;
    rslt = 1;
    printf("-- Testing %s ... ",name);
}

//  utility function
void TestEnd()
{
    if (rslt) tests_passed++;
    printf("%s\n", rslt ? "success" : "fail");
}

// stub function
void exit(int code)
{
    if (!done)
    {
        assert(should_exit==1);
        assert(expected_code==code);
        longjmp(jump_env, 1);
    }
    else
    {
        _exit(code);
    }
}

// test case
void test_normal()
{
    int jmp_rval;
    int r;

    TestStart("test_normal");
    should_exit = 0;
    if (!(jmp_rval=setjmp(jump_env)))
    {
        r = my_div(12,3);
    }

    assert(jmp_rval==0);
    assert(r==4);
    TestEnd();
}

// test case
void test_div0()
{
    int jmp_rval;
    int r;

    TestStart("test_div0");
    should_exit = 1;
    expected_code = 2;
    if (!(jmp_rval=setjmp(jump_env)))
    {
        r = my_div(2,0);
    }

    assert(jmp_rval==1);
    TestEnd();
}

int main()
{
    num_tests = 0;
    tests_passed = 0;
    done = 0;
    test_normal();
    test_div0();
    printf("Total tests passed: %d\n", tests_passed);
    done = 1;
    return !(tests_passed == num_tests);
}

এই উদাহরণস্বরূপ, আপনি setjmpপরীক্ষা করতে ফাংশনে প্রবেশের আগে ব্যবহার করেন , তারপরে স্ট্যাবডে exitআপনি longjmpসরাসরি নিজের পরীক্ষার ক্ষেত্রে ফিরে যেতে কল করেন।

এছাড়াও নোট করুন যে পুনরায় সংজ্ঞায়িত exitএকটি বিশেষ চলক রয়েছে যা এটি আপনাকে প্রোগ্রাম থেকে প্রকৃতপক্ষে প্রস্থান করতে চান এবং তা করার _exitজন্য কল করে কিনা তা যাচাই করে । আপনি যদি এটি না করেন তবে আপনার পরীক্ষা প্রোগ্রামটি পরিষ্কারভাবে ছাড়তে পারে না।


7

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

কোডটি কীভাবে এটি ব্যবহার করে তা দেখে এর একটি নমুনা এখানে দেওয়া হয়েছে:

try
{
    *((int *)0) = 0;    /* may not be portable */
}
catch (SegmentationFault, e)
{
    long f[] = { 'i', 'l', 'l', 'e', 'g', 'a', 'l' };
    ((void(*)())f)();   /* may not be portable */
}
finally
{
    return(1 / strcmp("", ""));
}

এবং এখানে অন্তর্ভুক্ত করা ফাইলটির অংশটিতে অনেক যুক্তি রয়েছে:

#ifndef _EXCEPT_H
#define _EXCEPT_H

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include "Lifo.h"
#include "List.h"

#define SETJMP(env)             sigsetjmp(env, 1)
#define LONGJMP(env, val)       siglongjmp(env, val)
#define JMP_BUF                 sigjmp_buf

typedef void (* Handler)(int);

typedef struct _Class *ClassRef;        /* exception class reference */
struct _Class
{
    int         notRethrown;            /* always 1 (used by throw()) */
    ClassRef    parent;                 /* parent class */
    char *      name;                   /* this class name string */
    int         signalNumber;           /* optional signal number */
};

typedef struct _Class Class[1];         /* exception class */

typedef enum _Scope                     /* exception handling scope */
{
    OUTSIDE = -1,                       /* outside any 'try' */
    INTERNAL,                           /* exception handling internal */
    TRY,                                /* in 'try' (across routine calls) */
    CATCH,                              /* in 'catch' (idem.) */
    FINALLY                             /* in 'finally' (idem.) */
} Scope;

typedef enum _State                     /* exception handling state */
{
    EMPTY,                              /* no exception occurred */
    PENDING,                            /* exception occurred but not caught */
    CAUGHT                              /* occurred exception caught */
} State;

typedef struct _Except                  /* exception handle */
{
    int         notRethrown;            /* always 0 (used by throw()) */
    State       state;                  /* current state of this handle */
    JMP_BUF     throwBuf;               /* start-'catching' destination */
    JMP_BUF     finalBuf;               /* perform-'finally' destination */
    ClassRef    class;                  /* occurred exception class */
    void *      pData;                  /* exception associated (user) data */
    char *      file;                   /* exception file name */
    int         line;                   /* exception line number */
    int         ready;                  /* macro code control flow flag */
    Scope       scope;                  /* exception handling scope */
    int         first;                  /* flag if first try in function */
    List *      checkList;              /* list used by 'catch' checking */
    char*       tryFile;                /* source file name of 'try' */
    int         tryLine;                /* source line number of 'try' */

    ClassRef    (*getClass)(void);      /* method returning class reference */
    char *      (*getMessage)(void);    /* method getting description */
    void *      (*getData)(void);       /* method getting application data */
    void        (*printTryTrace)(FILE*);/* method printing nested trace */
} Except;

typedef struct _Context                 /* exception context per thread */
{
    Except *    pEx;                    /* current exception handle */
    Lifo *      exStack;                /* exception handle stack */
    char        message[1024];          /* used by ExceptGetMessage() */
    Handler     sigAbrtHandler;         /* default SIGABRT handler */
    Handler     sigFpeHandler;          /* default SIGFPE handler */
    Handler     sigIllHandler;          /* default SIGILL handler */
    Handler     sigSegvHandler;         /* default SIGSEGV handler */
    Handler     sigBusHandler;          /* default SIGBUS handler */
} Context;

extern Context *        pC;
extern Class            Throwable;

#define except_class_declare(child, parent) extern Class child
#define except_class_define(child, parent)  Class child = { 1, parent, #child }

except_class_declare(Exception,           Throwable);
except_class_declare(OutOfMemoryError,    Exception);
except_class_declare(FailedAssertion,     Exception);
except_class_declare(RuntimeException,    Exception);
except_class_declare(AbnormalTermination, RuntimeException);  /* SIGABRT */
except_class_declare(ArithmeticException, RuntimeException);  /* SIGFPE */
except_class_declare(IllegalInstruction,  RuntimeException);  /* SIGILL */
except_class_declare(SegmentationFault,   RuntimeException);  /* SIGSEGV */
except_class_declare(BusError,            RuntimeException);  /* SIGBUS */


#ifdef  DEBUG

#define CHECKED                                                         \
        static int checked

#define CHECK_BEGIN(pC, pChecked, file, line)                           \
            ExceptCheckBegin(pC, pChecked, file, line)

#define CHECK(pC, pChecked, class, file, line)                          \
                 ExceptCheck(pC, pChecked, class, file, line)

#define CHECK_END                                                       \
            !checked

#else   /* DEBUG */

#define CHECKED
#define CHECK_BEGIN(pC, pChecked, file, line)           1
#define CHECK(pC, pChecked, class, file, line)          1
#define CHECK_END                                       0

#endif  /* DEBUG */


#define except_thread_cleanup(id)       ExceptThreadCleanup(id)

#define try                                                             \
    ExceptTry(pC, __FILE__, __LINE__);                                  \
    while (1)                                                           \
    {                                                                   \
        Context *       pTmpC = ExceptGetContext(pC);                   \
        Context *       pC = pTmpC;                                     \
        CHECKED;                                                        \
                                                                        \
        if (CHECK_BEGIN(pC, &checked, __FILE__, __LINE__) &&            \
            pC->pEx->ready && SETJMP(pC->pEx->throwBuf) == 0)           \
        {                                                               \
            pC->pEx->scope = TRY;                                       \
            do                                                          \
            {

#define catch(class, e)                                                 \
            }                                                           \
            while (0);                                                  \
        }                                                               \
        else if (CHECK(pC, &checked, class, __FILE__, __LINE__) &&      \
                 pC->pEx->ready && ExceptCatch(pC, class))              \
        {                                                               \
            Except *e = LifoPeek(pC->exStack, 1);                       \
            pC->pEx->scope = CATCH;                                     \
            do                                                          \
            {

#define finally                                                         \
            }                                                           \
            while (0);                                                  \
        }                                                               \
        if (CHECK_END)                                                  \
            continue;                                                   \
        if (!pC->pEx->ready && SETJMP(pC->pEx->finalBuf) == 0)          \
            pC->pEx->ready = 1;                                         \
        else                                                            \
            break;                                                      \
    }                                                                   \
    ExceptGetContext(pC)->pEx->scope = FINALLY;                         \
    while (ExceptGetContext(pC)->pEx->ready > 0 || ExceptFinally(pC))   \
        while (ExceptGetContext(pC)->pEx->ready-- > 0)

#define throw(pExceptOrClass, pData)                                    \
    ExceptThrow(pC, (ClassRef)pExceptOrClass, pData, __FILE__, __LINE__)

#define return(x)                                                       \
    {                                                                   \
        if (ExceptGetScope(pC) != OUTSIDE)                              \
        {                                                               \
            void *      pData = malloc(sizeof(JMP_BUF));                \
            ExceptGetContext(pC)->pEx->pData = pData;                   \
            if (SETJMP(*(JMP_BUF *)pData) == 0)                         \
                ExceptReturn(pC);                                       \
            else                                                        \
                free(pData);                                            \
        }                                                               \
        return x;                                                       \
    }

#define pending                                                         \
    (ExceptGetContext(pC)->pEx->state == PENDING)

extern Scope    ExceptGetScope(Context *pC);
extern Context *ExceptGetContext(Context *pC);
extern void     ExceptThreadCleanup(int threadId);
extern void     ExceptTry(Context *pC, char *file, int line);
extern void     ExceptThrow(Context *pC, void * pExceptOrClass,
                            void *pData, char *file, int line);
extern int      ExceptCatch(Context *pC, ClassRef class);
extern int      ExceptFinally(Context *pC);
extern void     ExceptReturn(Context *pC);
extern int      ExceptCheckBegin(Context *pC, int *pChecked,
                                 char *file, int line);
extern int      ExceptCheck(Context *pC, int *pChecked, ClassRef class,
                            char *file, int line);


#endif  /* _EXCEPT_H */

এখানে একটি সি মডিউলও রয়েছে যাতে সংকেত হ্যান্ডলিং এবং কিছু বুককিপিংয়ের যুক্তি রয়েছে।

আমি আপনাকে বলতে পারি এটি বাস্তবায়ন করা অত্যন্ত জটিল ছিল এবং আমি প্রায় ছেড়ে দিয়েছি। আমি এটিকে যতটা সম্ভব জাভার কাছাকাছি করার জন্য সত্যই চাপ দিয়েছি; আমি অবাক করে দিয়েছি যে আমি কেবল সি দিয়ে কতটা দূরে এসেছি

আপনার আগ্রহ থাকলে আমাকে চিৎকার করুন।


4
আমি আশ্চর্য হয়েছি কাস্টম ব্যতিক্রমগুলির জন্য প্রকৃত সংকলক সমর্থন ছাড়াই এটি সম্ভব। তবে সত্যিই মজার বিষয় হল সংকেতগুলি কীভাবে ব্যতিক্রমে রূপান্তরিত হয়।
পল স্টেলিয়ান

আমি একটি জিনিস জিজ্ঞাসা করব: ব্যতিক্রম যে শেষ পর্যন্ত না ধরা পরে? কীভাবে প্রধান () প্রস্থান করবেন?
পল স্টেলিয়ান

4
@ পলস্টেলিয়ান এবং, কীভাবে অপ্রয়োজনীয় প্রযোজনায় প্রস্থান করা হবে সে সম্পর্কে আপনার উত্তর এখানেmain() । দয়া করে এই উত্তরটি upvote করুন :-)
অর্থ-বিষয়গুলি

4
@ পলস্টেলিয়ান আহ, আমি এখন আপনাকে কী বোঝাতে চাইছি তা দেখতে পাচ্ছি। রান-টাইম ব্যতিক্রমগুলি যা ধরা পড়ে না বলে আমি বিশ্বাস করি আবার উত্থাপিত হয়েছিল যাতে সাধারণ (প্ল্যাটফর্ম নির্ভর) উত্তরটি প্রয়োগ হয়। ধরা পড়ে না কাস্টম ব্যতিক্রমগুলি মুদ্রিত এবং উপেক্ষা করা হয়েছিল। README এরProgagation বিভাগটি দেখুন আমি আমার এপ্রিল 1999 কোডটি গিটহাবে পোস্ট করেছি (সম্পাদিত উত্তরের লিঙ্কটি দেখুন)। একবার দেখুন; এটি ফাটানো একটি শক্ত বাদাম ছিল। আপনার মতামত শুনে ভাল লাগবে।
অর্থ-বিষয়গুলি

4
README এ একটি সংক্ষিপ্ত চেহারা ছিল, সেখানে খুব সুন্দর। সুতরাং এটি মূলত এটি বহিরাগত চেষ্টা ব্লকে প্রচার করে এবং এটি জাভাস্ক্রিপ্টের অ্যাসিঙ্ক ফাংশনগুলির অনুরূপ রিপোর্ট করা হয়। ভাল লাগল আমি পরে সোর্স কোডটি দেখব।
পল স্টেলিয়ান

1

হ্যান্ডস ডাউন, সেটজ্যাম্প / লংজ্যাম্পের সবচেয়ে গুরুত্বপূর্ণ ব্যবহার হ'ল এটি একটি "অ-স্থানীয় গোটো জাম্প" কাজ করে acts গোটো কমান্ড (এবং এমন বিরল উদাহরণ রয়েছে যেখানে আপনাকে লুপগুলির জন্য এবং যখন গোটো ব্যবহার করতে হবে) একই স্কোপটিতে সর্বাধিক-ব্যবহারযোগ্য। আপনি যদি স্কোপগুলি (বা অটো বরাদ্দ জুড়ে) জুড়ে ঝাঁপ দিতে গোটো ব্যবহার করেন তবে আপনি সম্ভবত আপনার প্রোগ্রামের স্ট্যাকটিকে দূষিত করবেন। setjmp / longjmp এটিকে এড়াতে আপনি যে স্থানে যেতে চান সেখানে স্ট্যাকের তথ্য সংরক্ষণ করে। তারপরে, আপনি যখন লাফ দিন, এটি এই স্ট্যাকের তথ্য লোড করে। এই বৈশিষ্ট্যটি ব্যতীত সি প্রোগ্রামাররা সম্ভবত সেটলজ্যাম্প / লংজ্যাম্প সমাধান করতে পারে এমন সমস্যাগুলি সমাধান করার জন্য অ্যাসেমব্লিলি প্রোগ্রামিংয়ের দিকে যেতে হবে। Godশ্বরের ধন্যবাদ এটি বিদ্যমান। সি লাইব্রেরির সমস্ত কিছুই অত্যন্ত গুরুত্বপূর্ণ। আপনার যখন প্রয়োজন হবে তখন আপনি জানতে পারবেন।


4
"সি লাইব্রেরির সমস্ত কিছুই অত্যন্ত গুরুত্বপূর্ণ" " লোকালগুলির মতো অবহেলিত সামগ্রী এবং স্টাফগুলির পুরো গুচ্ছটি কখনও ভাল ছিল না।
Qwr

0

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

ধারাবাহিকতা পাসিং স্টাইলে ইনপুট কোডটি রূপান্তর না করে এটি সি তে ক্রমাগত বাস্তবায়ন হয়।

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