আপনার প্রিয় সি প্রোগ্রামিং কৌশলটি কী? [বন্ধ]


134

উদাহরণস্বরূপ, আমি সম্প্রতি লিনাক্স কার্নেল এ জুড়ে এসেছি:

/ * শর্তটি সত্য হলে সংকলনের ত্রুটি জোর করুন * /
# নির্ধারিত বিল্ড_বিউজিউথিউট (শর্ত) ((শূন্য) আকারের (চর [1 - 2 * !! (শর্ত)]))

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

BUILD_BUGटका ((মাপের (স্ট্রাক মাইস্ট্রাক)% 8)! = 0);

এবং স্ট্রাক্ট মাইস্ট্রাকটের আকারটি 8 এর একাধিক না হওয়া পর্যন্ত এটি সংকলন করবে না এবং এটি 8 এর একাধিক হলে কোনও রানটাইম কোড তৈরি করা হবে না।

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

#ifdef DEFINE_MYHEADER_GLOBALS
বিশ্বব্যাপী
# নির্ধারণ INIT (x, y) (x) = (y)
#else
বিশ্বব্যাপী বাহ্যিক নির্ধারণ করুন
# নির্ধারিত আইএনআইটি (x, y)
#যদি শেষ

গ্লোবাল ইন আইএনআইটি (এক্স, 0);
গ্লোবাল ইন সামফুঙ্ক (ইন এ, ইনট বি);

এটির সাথে, কোডটি যা এক্স এবং কিছু সংখ্যককে সংজ্ঞায়িত করে:

# ডেফাইন DEFINE_MYHEADER_GLOBALS
# অন্তর্ভুক্ত করুন

কোডটি যখন কেবল x এবং সামুফঙ্ক () ব্যবহার করে:

# অন্তর্ভুক্ত করুন

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

সুতরাং, সেই লাইনের সাথে আপনার প্রিয় সি প্রোগ্রামিং কৌশলগুলি কী কী?


9
এটি সি প্রিপ্রসেসর কৌশলগুলির মতো মনে হয়।
jmucchiello

BUILD_BUG_ONম্যাক্রো সম্পর্কে , #errorভিতরে ব্যবহার করে এবং এর সাথে কী ভুল #if?
রিকার্ডো

উত্তর:


80

C99 বেনামে অ্যারে ব্যবহার করে কিছু সত্যই শীতল জিনিস সরবরাহ করে:

অর্থহীন ভেরিয়েবলগুলি অপসারণ করা হচ্ছে

{
    int yes=1;
    setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}

হয়ে

setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

তর্কগুলির একটি পরিবর্তনীয় পরিমাণ পাস করা

void func(type* values) {
    while(*values) {
        x = *values++;
        /* do whatever with x */
    }
}

func((type[]){val1,val2,val3,val4,0});

স্থিতিশীল লিঙ্ক তালিকা

int main() {
    struct llist { int a; struct llist* next;};
    #define cons(x,y) (struct llist[]){{x,y}}
    struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
    struct llist *p = list;
    while(p != 0) {
        printf("%d\n", p->a);
        p = p->next;
    }
}

যে কোনও আমি নিশ্চিত যে অন্যান্য অনেক দুর্দান্ত কৌশলগুলি আমি ভেবে দেখিনি।


2
আমি বিশ্বাস করি যে আপনার প্রথম উদাহরণটিও এ হিসাবে লেখা যেতে পারে &(int){1}, আপনি যদি এখানে কিছুটা পরিষ্কার করতে চান তবে আপনার উদ্দেশ্য কী।
লিলি বালার্ড

67

ভূমিকম্প 2 উত্স কোড পড়ার সময় আমি এরকম কিছু নিয়ে এসেছি:

double normals[][] = {
  #include "normals.txt"
};

(কম-বেশি, এখনই এটি পরীক্ষা করার কোড আমার কাছে নেই)।

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

ধন্যবাদ জন কারম্যাক! xD


13
আপনি ভূমিকম্পের উত্সটিতে থাকা দ্রুত বিপরীত স্কয়ার্টের উল্লেখ না করে কোনও অপ্টিমাইজেশন থ্রেডে কারম্যাক বলতে পারবেন না। en.wikipedia.org/wiki/Fast_inverse_square_root
pg1989

তিনি প্রথম স্থান থেকে কোথা থেকে 0x5f3759df পেয়েছেন?
আরএসএইচ 1

2
@ ররিহারভে: এটি সন্ধান করার সময় আমি যা খুঁজে পেলাম তা থেকে মনে হয় এটি নিখুঁতভাবে অভিজ্ঞতাবাদী ছিল। কিছু অধ্যয়ন (যেখানে আমি সেগুলি দেখেছিলাম তা মনে নেই) প্রমাণ করে যে এটি অনুকূলের নিকটে, তবে পুরোপুরি অনুকূল নয়। তেমনি, দেখে মনে হয় যে 64 বিবিটের জন্য মানটি গণনা করার পরিবর্তে আবিষ্কার করা হয়েছিল।
ম্যাথিউ এম।

50

আমি = {0};মেমসেট কল করার প্রয়োজন ছাড়াই কাঠামোগুলি আরম্ভ করার জন্য ব্যবহারের অনুরাগী ।

struct something X = {0};

এটি স্ট্রাক্টের সমস্ত সদস্যকে (বা অ্যারে) শূন্যে শুরু করবে (তবে কোনও প্যাডিং বাইট নয় - মেমসেট ব্যবহার করুন যদি আপনারও শূন্য করতে হয়)।

তবে আপনার সচেতন হওয়া উচিত বৃহত, গতিশীল বরাদ্দ কাঠামোর জন্য এটিতে কিছু সমস্যা রয়েছে


গ্লোবাল ভেরিয়েবলের জন্য প্রয়োজন হয় না।
স্টারগার

5
স্ট্যাটিক ভেরিয়েবলের জন্য প্রয়োজন হয় না । গ্লোবাল ভেরিয়েবলগুলি শূন্য করা যেতে পারে তবে এটির প্রয়োজন নেই।
জেমি

4
আমি মাঝে মাঝে এটিতে প্রসারিত করি: const struct something zero_something = { 0 };এবং তারপরে আমি struct something X = zero_something;'এক্স = শূন্য_সামনিথিং;' ব্যবহার করতে পারি এমন একটি রুটিনের মাধ্যমে ফ্লাইতে বা পার্ট-ওয়ে দিয়ে একটি পরিবর্তনশীল পুনরায় সেট করতে পারি । একমাত্র সম্ভাব্য আপত্তিটি হ'ল এতে কোথাও থেকে আসা ডেটা পড়া জড়িত; এই দিনগুলিতে একটি 'মেমসেট ()' দ্রুত হতে পারে - তবে আমি নির্ধারিত স্পষ্টতার বিষয়টি পছন্দ করি এবং ইনিশিয়ালারে শূন্যের চেয়ে অন্যান্য মানগুলিও ব্যবহার করা সম্ভব (এবং মেমসেট () তার পরে পৃথক সদস্যকে টুইট করে) সাধারণ কপির চেয়ে ধীর হতে পারে)।
জোনাথন লেফলার

45

আমরা যদি সি ট্রিক্সের কথা বলি তবে আমার পছন্দটি লুপ আন্রোলিংয়ের জন্য ডাফের ডিভাইস হতে হবে ! আমি কেবল ক্রোধে এটি ব্যবহার করার জন্য সঠিক সুযোগের অপেক্ষায় আছি ...


4
পরিমাপযোগ্য পারফরম্যান্স লাভের জন্য আমি এটি একবার ব্যবহার করেছি, তবে আজকাল এটি বেশিরভাগ হার্ডওয়্যারে কার্যকর নয়। সর্বদা প্রোফাইল!
ড্যান অলসন

6
হ্যাঁ, ডফের ডিভাইসটি প্রসঙ্গটি বোঝে না এমন ধরণের লোকগুলি তৈরি করা হয়েছিল: কোডটি কাজ করার জন্য পর্যাপ্ত দ্রুত না হলে "কোড পাঠযোগ্যতা" অকেজো। সম্ভবত আপনাকে হ্রাসকারী লোকদের মধ্যে কেউই কখনও হার্ড রিয়েলটাইমের জন্য কোড করতে পারেনি।
রব কে

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

3
ক্রোধটি আপনার সহকর্মীদের এবং উত্তরসূরিদের কাছ থেকে আসবে যারা আপনার পরে আপনার কোড বজায় রাখতে হবে।
জোনাথন লেফলার

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

42

ডিবাগিং __FILE__এবং ব্যবহারের __LINE__জন্য

#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);

6
কিছু সংকলকগুলিতে আপনি পাশাপাশি ফাংশন পান।
জেবিআরউইলকিনসন

11
__FUNCTION__এটির জন্য কেবল একটি উপনাম __func__, এবং __func__সি 99 এ রয়েছে। বেশ সহজ। __PRETTY_FUNCTION__সি (জিসিসি) এর জন্য অন্য একটি উপন্যাস __func__, তবে সি ++ এ এটি আপনাকে পুরো ফাংশনের স্বাক্ষর পাবে।
sklnd

ফাইল ফাইলের পুরো পথ দেখায় তাই আমি
বেসনাম


28

একবার আমার এবং আমার সঙ্গী একবার একটি কৌশলযুক্ত স্ট্যাক দুর্নীতির বাগ খুঁজে পেতে পুনরায় সংজ্ঞা দিয়েছিলেন।

কিছুটা এইরকম:

#define return DoSomeStackCheckStuff, return

4
আশা করি এটি ফাংশন বডিটিতে # সংজ্ঞায়িত করা হয়েছিল এবং শেষ পর্যন্ত # অপরিবর্তিত ছিল!
স্ট্রাগার

এটির খুব পছন্দ নয় - প্রথম যে বিষয়টি আমার মনে আসে তা হ'ল কিছু বগের কারণে ডসোমস্ট্যাকচেকস্টফ মেমরিটি স্ক্রু করে দেয় এবং যে কেউ কোডটি পড়ছে তারা ফেরতের পুনঃনির্ধারণ সম্পর্কে অবগত নয় এবং অবাক হয় যে / নরক / কী চলছে।
গিলিগান

8
@ স্ট্রাজার তবে এটি মূলত অকেজো হয়ে যাবে। পুরো পয়েন্টটি হ'ল প্রতিটি ফাংশন কলে কিছু ট্রেসিং যুক্ত করা । অন্যথায় আপনি DoSomeStackCheckStuffযে ফাংশনগুলি ট্রেস করতে চেয়েছিলেন তাতে আপনি কেবল একটি কল যুক্ত করবেন ।
ক্লুলেস

1
@ গিলিগান আমি মনে করি না যে এটি আপনি সর্বদা সক্ষম রেখে গেছেন এমন জিনিস; এক-শট ডিবাগিং কাজের জন্য এটি বেশ সহজ বলে মনে হচ্ছে।
সনেটোস

এটা কি সত্যিই কাজ করে? :) আমি লিখতাম #define return if((DoSomeStackCheckStuff) && 0) ; else return... ঠিক তেমন পাগল আমার ধারণা!
পাওলো বনজিণী

22

গতিশীল আকারের অবজেক্ট থাকার জন্য আমি "স্ট্রাক হ্যাক" পছন্দ করি। এই সাইটটি এটি বেশ সুন্দরভাবে ব্যাখ্যা করেছে (যদিও তারা C99 সংস্করণটি উল্লেখ করে যেখানে আপনি কোনও স্ট্রাক্টের শেষ সদস্য হিসাবে "str []" লিখতে পারেন)। আপনি এভাবে স্ট্রিং "অবজেক্ট" তৈরি করতে পারেন:

struct X {
    int len;
    char str[1];
};

int n = strlen("hello world");
struct X *string = malloc(sizeof(struct X) + n);
strcpy(string->str, "hello world");
string->len = n;

এখানে, আমরা স্তূপে X টাইপের একটি কাঠামো বরাদ্দ করেছি যা কোনও int এর আকার (লেনের জন্য), এবং "হ্যালো ওয়ার্ল্ড" এর দৈর্ঘ্য, প্লাস 1 (যেহেতু আরআর 1 মাপের (এক্স) এর অন্তর্ভুক্ত রয়েছে)।

এটি একই সময়ে কার্যকর যখন আপনি একই ব্লকের কিছু পরিবর্তনশীল দৈর্ঘ্যের ডেটার ঠিক আগে "শিরোনাম" রাখতে চান।


আমি ব্যক্তিগতভাবে কেবলমাত্র malloc () এবং রিলোক () নিজেকে এবং স্ট্রেন () ব্যবহার করতে যখনই আমার দৈর্ঘ্য সন্ধান করার প্রয়োজন হয়, তবে এটির জন্য যদি আপনার এমন কোনও প্রোগ্রামের প্রয়োজন হয় যা স্ট্রিংয়ের দৈর্ঘ্যটি কখনই জানেন না এবং সম্ভবত এটির অনেকগুলি সন্ধান করার প্রয়োজন হবে বার, এটি সম্ভবত ভাল রাস্তা।
ক্রিস লুটজ

4
"... C99 সংস্করণ যেখানে আপনি লিখতে পারবেন" str [] "" আমি এই জাতীয় প্রসঙ্গে শূন্য আকারের অ্যারেগুলি দেখেছি, [0]; মাঝে মধ্যেই. আমি মনে করি এটি C99। আমি জানি পুরানো সংকলকরা যদিও শূন্য আকারের অ্যারে সম্পর্কে অভিযোগ করেন।
স্মোক্যামেরন 8

3
আমি এটিকেও পছন্দ করি তবে যাইহোক, আপনি ম্যালোক (অফসেটফ (এক্স, টিআর) + নামবিটস) এর মতো কিছু ব্যবহার করুন অন্যথায় প্যাডিং এবং প্রান্তিককরণ সমস্যার কারণে জিনিসগুলি ভুল হয়ে যাবে। উদাহরণস্বরূপ (স্ট্রাক্ট এক্স) 8 টি হতে পারে, 5 টি নয়
ফোজি

3
@ ফোজি: আমি আসলে মনে করি না যে এটি কোনও সমস্যা হবে। যেহেতু এই সংস্করণটিতে str[1](নয় str[]) 1 বাইট অফ স্ট্রিংটি অন্তর্ভুক্ত রয়েছে sizeof(struct X)। এর মধ্যে এবং এর মধ্যে যে কোনও প্যাডিং রয়েছে । lenstr
ইভান তেরান

2
@ রুস্কি: কীভাবে এটি কোনও কিছুর নেতিবাচক প্রভাব ফেলবে? ধরুন এর পরে "প্যাডিং" আছে str। ঠিক আছে, যখন আমি বরাদ্দ করি sizeof(struct X) + 10তারপরে এটি strকার্যকরভাবে 10 - sizeof(int)(বা আরও বেশি, যেহেতু আমরা বলেছি প্যাডিং রয়েছে) বড় করে তোলে । এটি ওভারলে str এবং এর পরে কোনও প্যাডিং। এটির যে কোনও পার্থক্য রয়েছে তার একমাত্র উপায় , যদি কোনও সদস্য থাকে strযার পরে যেভাবেই পুরো জিনিসটি ভেঙে যায়, নমনীয় সদস্যদের অবশ্যই শেষ হতে হবে। শেষে যে কোনও প্যাডিং কেবলমাত্র খুব বেশি বরাদ্দ পাবে। এটি কীভাবে আসলে ভুল হতে পারে তার একটি নির্দিষ্ট উদাহরণ সরবরাহ করুন।
ইভান তেরান

17

ক্লাস অনুকরণ করে সি দিয়ে অবজেক্ট ওরিয়েন্টেড কোড।

কেবলমাত্র একটি কাঠামো এবং ফাংশনগুলির একটি সেট তৈরি করুন যা সেই স্ট্রাক্টকে প্রথম পরামিতি হিসাবে নিয়ে যায়।


2
সিফ্রন্ট যেমন ব্যবহার করত তেমন কি এখনও কিছু আছে যা সি ++ কে সিতে অনুবাদ করে?
মার্কজে

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

বলা প্রয়োজন। তার জন্য +1।
অমিত এস

3
@ exDM69, অবজেক্ট অরিয়েন্টেশন যেমন কোনও কোডিং দৃষ্টান্ত হিসাবে কোনও সমস্যা নিয়ে ভাবনা ততটুকু উপায়; উত্তরাধিকার ছাড়াই আপনি সফলভাবে এটি করতে পারেন। আমি পুরো বোরকে সি ++ এ ঝাঁপ দেওয়ার আগে কয়েকটি প্রকল্পে এটি করেছি।
মার্ক রান্সম

16

পরিবর্তে

printf("counter=%d\n",counter);

ব্যবহার

#define print_dec(var)  printf("%s=%d\n",#var,var);
print_dec(counter);

14

রেকর্ড সংজ্ঞা বজায় রাখা সহজ করার জন্য বোকা ম্যাক্রো ট্রিক ব্যবহার করা।

#define COLUMNS(S,E) [(E) - (S) + 1]

typedef struct
{
    char studentNumber COLUMNS( 1,  9);
    char firstName     COLUMNS(10, 30);
    char lastName      COLUMNS(31, 51);

} StudentRecord;

11

একটি ভেরিয়েবল তৈরি করার জন্য যা কেবলমাত্র মডিউলগুলিতে কেবল এটির মধ্যে ঘোষণা করা ছাড়া কেবল পঠনযোগ্য:

// Header1.h:

#ifndef SOURCE1_C
   extern const int MyVar;
#endif

// Source1.c:

#define SOURCE1_C
#include Header1.h // MyVar isn't seen in the header

int MyVar; // Declared in this file, and is writeable

// Source2.c

#include Header1.h // MyVar is seen as a constant, declared elsewhere

এটি বিপজ্জনক বোধ করে। এগুলি ঘোষণা এবং সংজ্ঞা যা মেলে না। সংকলন করার সময়, সংকলকটি Source2.cধরে নিতে পারে যে এটি MyVarপরিবর্তন হয় না, এমনকি কোনও ফাংশন কল পর্যন্ত Source1.c। (নোট যে এই, প্রকৃত const পরিবর্তনশীল হিসাবে, const একটি পয়েন্টার থেকে পৃথক পরেরটির ক্ষেত্রে, সরু-টু সে আপত্তি এখনও একটি ভিন্ন পয়েন্টার মাধ্যমে পরিবর্তিত হতে পারে।।)
jilles

1
এটি পরিবর্তনশীল উত্পাদন করে না যা কেবলমাত্র কয়েকটি সংকলন ইউনিটে কেবলমাত্র পঠনযোগ্য। এটি অপরিবর্তিত আচরণ তৈরি করে (আইএসও 9899 এর পৃষ্ঠা 6.2.7.2 এবং পি। 6.7.3.5 দেখুন)।
আলেস হাকল

8

বিট-শিফটগুলি কেবলমাত্র 31 এর শিফ্ট-পরিমাণ (32 বিট সংখ্যায়) পর্যন্ত সংজ্ঞায়িত করা হয় ..

আপনি যদি এমন একটি গণনাকারী শিফট রাখতে চান যা উচ্চতর শিফ্ট-মানগুলির সাথেও কাজ করা প্রয়োজন তবে আপনি কী করবেন? থিওড়া ভিডিও-কোডেক এটি করে কীভাবে তা এখানে রয়েছে:

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  return (a>>(v>>1))>>((v+1)>>1);
}

বা আরও অনেক পাঠযোগ্য:

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  unsigned int halfshift = v>>1;
  unsigned int otherhalf = (v+1)>>1;

  return (a >> halfshift) >> otherhalf; 
}

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

unsigned int shiftmystuff (unsigned int a, unsigned int v)
{
  if (v<=31)
    return a>>v;
  else
    return 0;
}

... এবং জিসিসি আসলে এটির সাথে যুক্ত করেছে :) +1
টিম পোস্ট

2
আমার মেশিনে, gcc-4.3.2 সেমিওভ নির্দেশিকা (শর্তসাপেক্ষে পদক্ষেপ) ব্যবহার করে দ্বিতীয়টিতে শাখাটি থেকে মুক্তি পেয়েছে
অ্যাডাম রোজেনফিল্ড

3
"একটি শাখা ব্যবহারের চেয়ে দ্রুত একটি ভাল চুক্তি": পার্থক্যটি হ'ল শাখাটি সমস্ত মানের জন্য সঠিক v, তবে halfshiftকৌশলটি কেবল 32-বিট আর্কিটেকচারে অনুমোদিত পরিসরটিকে দ্বিগুণ করে এবং 64-বিট একটিতে 127 করে দেয়।
পাস্কেল কুয়াক

8

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

int (* fsm[])(void) = { ... }

সর্বাধিক আনন্দদায়ক সুবিধা হ'ল প্রতিটি উদ্দীপনা / রাষ্ট্রকে সমস্ত কোড পাথ চেক করতে বাধ্য করা সহজ।

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


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

7

আর একটি দুর্দান্ত প্রসেসর "কৌশল" হ'ল ডিবাগিং এক্সপ্রেশনগুলি মুদ্রণের জন্য "#" অক্ষরটি ব্যবহার করা। উদাহরণ স্বরূপ:

#define MY_ASSERT(cond) \
  do { \
    if( !(cond) ) { \
      printf("MY_ASSERT(%s) failed\n", #cond); \
      exit(-1); \
    } \
  } while( 0 )

সম্পাদনা করুন: নীচের কোডটি কেবল সি ++ এ কাজ করে। স্মাক্যামেরন এবং ইভান তেরানকে ধন্যবাদ।

হ্যাঁ, সংকলনের সময় দাবি সর্বদা দুর্দান্ত। এটি এই হিসাবে লেখা যেতে পারে:

#define COMPILE_ASSERT(cond)\
     typedef char __compile_time_assert[ (cond) ? 0 : -1]

COMPILE_ASSERT ম্যাক্রো দু'বার ব্যবহার করা যাবে না, কারণ এটি টাইপডেফের সাথে নাম স্থানটিকে দূষিত করে এবং দ্বিতীয় ব্যবহারটি পায়: ত্রুটি: টাইপডেফের __compile_time_assert '
স্ম্যাক ক্যামেরন

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


1
হ্যাঁ, আমি চেষ্টা করেছিলাম। আমি সংস্থাপকটির ত্রুটি বার্তাটি কেটে পেস্ট করেছি, এটি ছিল জিসিসি।
স্মাচেমেরন

1
@ গিলাদ: রিডানড্যান্ট টাইপডেফ রাখা সি ++ তে বৈধ, তবে সি তে নয়।
ইভান তেরান

6

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


কোড ড্রাইভিংকে নির্ভরশীল অ্যাসিনক্রোনাস আই / হে অস্পষ্টভাবে মানব-পঠনযোগ্যের ক্রম হিসাবে তৈরি করতে আমি বাস্তবে এই কৌশলটি ব্যবহার করেছি। মূল পার্থক্যটি হ'ল আমি কোনও staticভেরিয়েবলে কর্টিন স্টেট সংরক্ষণ করি না বরং পরিবর্তে একটি স্ট্রাক্টকে গতিশীলভাবে বরাদ্দ করি এবং এতে একটি পয়েন্টারটি কর্টিন ফাংশনে প্রবেশ করি। একগুচ্ছ ম্যাক্রো এটি আরও স্বচ্ছল করে তোলে। এটি পুরো জায়গা জুড়ে ছড়িয়ে পড়া অ্যাসিঙ্ক / কলব্যাক সংস্করণটির চেয়ে সুন্দর নয়। আমি swapcontext()পারলে সবুজ থ্রেড ( * নিক্সের মাধ্যমে ) ব্যবহার করতাম ।
pmdj

6
#if TESTMODE == 1    
    debug=1;
    while(0);     // Get attention
#endif

যখন (0); প্রোগ্রামটিতে কোনও প্রভাব ফেলেনি, তবে সংকলক "এটি কিছুই করে না" সম্পর্কে একটি সতর্কতা জারি করবে, যা আমাকে আপত্তিজনক লাইনে দেখার জন্য প্রস্তুত করা এবং তারপরে আমি এটির দিকে নজর দেওয়ার প্রকৃত কারণটি দেখতে যথেষ্ট।


9
আপনি কি পরিবর্তে # তড়িৎ ব্যবহার করতে পারবেন না?
স্টেফানো বোরিনি

স্পষ্টতই, আমি পারলাম। এটি সম্পূর্ণ স্ট্যান্ডার্ড নয়, তবে এটি যে সংকলকগুলি আমি ব্যবহার করি তাতে এটি কাজ করে। মজার বিষয় হল, এম্বেড করা সংকলক একটি # ডেফাইন অনুবাদ করেছেন, যখন জিসিসি তা করেনি।
গুবারি

6

আমি জোর হ্যাকের ভক্ত:

তৃতীয় টেম্প পয়েন্টার ছাড়াই 2 পয়েন্টার অদলবদল করুন:

int * a;
int * b;
a ^= b;
b ^= a;
a ^= b;

অথবা আমি কেবলমাত্র একটি পয়েন্টার সহ xor লিঙ্কযুক্ত তালিকাটি পছন্দ করি। (Http://en.wikipedia.org/wiki/XOR_linked_list)

লিঙ্কযুক্ত তালিকার প্রতিটি নোড পূর্ববর্তী নোডের জোর এবং পরবর্তী নোড। এগিয়ে যেতে, নোডগুলির ঠিকানা নিম্নলিখিত পদ্ধতিতে পাওয়া যায়:

LLNode * first = head;
LLNode * second = first.linked_nodes;
LLNode * third = second.linked_nodes ^ first;
LLNode * fourth = third.linked_nodes ^ second;

প্রভৃতি

বা পিছনের দিকে যেতে:

LLNode * last = tail;
LLNode * second_to_last = last.linked_nodes;
LLNode * third_to_last = second_to_last.linked_nodes ^ last;
LLNode * fourth_to_last = third_to_last.linked_nodes ^ second_to_last;

প্রভৃতি

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


5

এটি 'পায়ে নিজেকে গুলি করার জন্য পর্যাপ্ত দড়ি' বইটি থেকে এসেছে:

শিরোনামে ঘোষণা করুন

#ifndef RELEASE
#  define D(x) do { x; } while (0)
#else
#  define D(x)
#endif

আপনার কোড প্লেসের পরীক্ষার বিবৃতি যেমন:

D(printf("Test statement\n"));

ম্যাক্রোর সামগ্রীগুলি একাধিক বিবৃতিতে প্রসারিত হওয়ার ক্ষেত্রে / করতে সহায়তা করে।

বিবৃতিটি কেবল তখনই মুদ্রিত হবে যখন সংকলকের জন্য '-D রিলিজ' পতাকা ব্যবহার করা হয়নি।

আপনি তারপর যেমন করতে পারেন। আপনার মেকফিল ইত্যাদিতে পতাকাটি প্রেরণ করুন

উইন্ডোজে এটি কীভাবে কাজ করে তা নিশ্চিত নয় তবে * নিক্সে এটি ভালভাবে কাজ করে


রিলে সংজ্ঞা দেওয়া হয় আপনি ডি (এক্স) কে {to এ প্রসারিত করতে চাইতে পারেন, যাতে বিবৃতি যদি এটির সাথে সুন্দর হয়। অন্যথায় "যদি (ক) ডি (এক্স);" যখন আপনার রিলিজের সংজ্ঞা দেওয়া হয়েছে কেবল "যদি (ক)" তে প্রসারিত হবে। এটি আপনাকে রিলেস ভেরিওনে কিছু ভাল বাগ দেবে
মার্কজে

3
@ মারকজে: না। উপায়টি, "যদি (ক) ডি (এক্স);" "যদি (ক)" তে প্রসারিত হয়; যা পুরোপুরি ঠিক আছে। আপনার যদি ডি (এক্স) প্রসারিত হয় {}, তবে "যদি (ক) যদি (খ) ডি (এক্স); অন্যথায় ফু ();" ভুলভাবে প্রসারিত হবে "যদি (ক) যদি (খ) যদি b expand; অন্যথায় foo ();", যার ফলে "অন্য কোনও foo ()" প্রথমটির পরিবর্তে দ্বিতীয়টির সাথে মিলিত হয় if
অ্যাডাম রোজেনফিল্ড

সত্যি কথা বলতে, আমি বেশিরভাগই এই ম্যাক্রোটি মুদ্রণ বিবৃতিগুলির পরীক্ষার জন্য ব্যবহার করি, বা যদি আমার শর্তাধীন বিবৃতি থাকে তবে আমি এগুলি সমস্ত বন্ধ করে দেব। ডি (যদি (ক) ফু (););
সাইমন ওয়াকার 13

1
@ অ্যাডামরোসনফিল্ড: #define D(x) do { } while(0)পরিবর্তে এই কেসটি পরিচালনা করে (এবং সেই শাখায় প্রয়োগ করা যেতে পারে যা xধারাবাহিকতার জন্য সন্নিবেশ
করানো হয়

3

মরিচা আসলে cnc এ বিল্ড কন্ডিশনালের পুরো সেট তৈরি করেছিল , বিল্ড অ্যাসেট মডিউলটি পরীক্ষা করে দেখুন:

#include <stddef.h>
#include <ccan/build_assert/build_assert.h>

struct foo {
        char string[5];
        int x;
};

char *foo_string(struct foo *foo)
{
        // This trick requires that the string be first in the structure
        BUILD_ASSERT(offsetof(struct foo, string) == 0);
        return (char *)foo;
}

আসল শিরোনামে প্রচুর অন্যান্য সহায়ক ম্যাক্রো রয়েছে যা এগুলিতে ফেলে দেওয়া সহজ।

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


হ্যাঁ, আমি সম্প্রতি ক্র্যাঙ্কটি পেরিয়ে এসেছি এবং কিছু কোড অবদানের কথা বিবেচনা করছি, তবে এখনও "মাথা চালানোর পথে" আমার মাথাটি জড়িয়ে নেই। যদিও লিঙ্কটির জন্য ধন্যবাদ, আরও বেশি অনুপ্রেরণা ccan দেখার জন্য, যা আমি সত্যিই আশা করি কিছুটা ট্র্যাকশন পেয়েছে gets
স্মোকামেরন

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

বিটিডাব্লু, আমি লক্ষ করেছি যে রুস্টির বিল্ড_এএসআরটিটি ঠিক লিনাক্স কার্নেলের ম্যাক্রোর মতো (উদ্বেগজনক) তবে একটি "নোট" (বা ব্যাঙ্গস, বা 'গুলি) অনুপস্থিত এবং লক্ষ্য করে, আমি মনে করি আমি পোস্ট করা ম্যাক্রোর উদাহরণ হিসাবে ব্যবহার করেছি সঠিক না. হওয়া উচিত ছিল: "BUILD_BUG_ON ((মাপের (স্ট্রাক্ট মাইস্ট্রাক)% 8%))"
স্মক্যামেরন

3

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


1
আফাইক, সি 98/90 এ এনামদের জন্য কোনও টাইপচেকিং নেই। এনামগুলি কোনওভাবেই # সুবিধাজনক #
cschol

39 পৃষ্ঠার নীচে, দ্বিতীয় ED কেএন্ডআর। অন্তত চেক করার সুযোগ আছে।
জোনাথন ওয়াটমু

3

সি এর সাথে নির্দিষ্ট নয় তবে আমি সবসময় এক্সওআর অপারেটরকে পছন্দ করেছি liked এটি করতে পারে এমন একটি দুর্দান্ত জিনিস হ'ল "সাময়িক মান ছাড়াই অদলবদল:"

int a = 1;
int b = 2;

printf("a = %d, b = %d\n", a, b);

a ^= b;
b ^= a;
a ^= b;

printf("a = %d, b = %d\n", a, b);

ফলাফল:

a = 1, খ = 2

a = 2, খ = 1


a = 1; খ = 2; a = a + b; খ = আব; a = ab; একই ফলাফলও দেয়
গ্রামবট

এটি a এবং b কেও অদলবদল করবে: a ^ = b ^ = a ^ = b;
উইকিয়ত

@ দ্য কেপএন: সংযোজন যদিও উপচে পড়বে।
মাইকেল ফৌকারকিস


2

আমি container_ofতালিকায় উদাহরণস্বরূপ ব্যবহৃত ধারণা পছন্দ করি । মূলত, আপনার তালিকার প্রতিটি কাঠামোর জন্য নির্দিষ্ট nextএবং lastক্ষেত্রগুলির প্রয়োজন হবে না। পরিবর্তে, আপনি প্রকৃত লিঙ্কযুক্ত আইটেমগুলিতে তালিকা কাঠামো শিরোনাম যুক্ত করুন।

একটি চেহারা আছে include/linux/list.hবাস্তব জীবনের উদাহরণ জন্য।


1

আমি মনে করি ইউজারডাটা পয়েন্টার ব্যবহারটি বেশ ঝরঝরে। আজকাল একটি ফ্যাশন হারানোর স্থল। এটি তেমন কোনও সি বৈশিষ্ট্য নয় তবে এটি সিতে ব্যবহার করা বেশ সহজ


1
আমি আশা করি যে আপনি এখানে বোঝাতে চেয়েছিলেন আমি বুঝতে পারি। আপনি আরও ব্যাখ্যা করতে পারেন? ইউজারডটা পয়েন্টার কী?
জ্যান লিংস

1
Plz এখানে দেখতে stackoverflow.com/questions/602826/...
epatel

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

অই হ্যাঁ. ধন্যবাদ। আমি এটিকে অনেক ব্যবহার করি, তবে আমি কখনই এটিকে ডাকিনি।
ঝ্যান লিংস

1

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


1

আমাদের কোডবেসের মতো কৌশল রয়েছে

#ifdef DEBUG

#define my_malloc(amt) my_malloc_debug(amt, __FILE__, __LINE__)
void * my_malloc_debug(int amt, char* file, int line)
#else
void * my_malloc(int amt)
#endif
{
    //remember file and line no. for this malloc in debug mode
}

যা ডিবাগ মোডে মেমরি ফাঁসের ট্র্যাকিংয়ের অনুমতি দেয়। আমি সবসময় মনে করি এটি দুর্দান্ত ছিল।


1

ম্যাক্রোগুলির সাথে মজা করুন:

#define SOME_ENUMS(F) \
    F(ZERO, zero) \
    F(ONE, one) \
    F(TWO, two)

/* Now define the constant values.  See how succinct this is. */

enum Constants {
#define DEFINE_ENUM(A, B) A,
    SOME_ENUMS(DEFINE_ENUMS)
#undef DEFINE_ENUM
};

/* Now a function to return the name of an enum: */

const char *ToString(int c) {
    switch (c) {
    default: return NULL; /* Or whatever. */
#define CASE_MACRO(A, B) case A: return #b;
     SOME_ENUMS(CASE_MACRO)
#undef CASE_MACRO
     }
}

0

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

এখানে সম্পূর্ণ সংকলনযোগ্য উদাহরণ যুক্ত করা হচ্ছে।

/* free.h */
#ifndef _FREE_H_
#define _FREE_H_
#include <stdio.h>
#include <string.h>
typedef unsigned char ubyte;

typedef void (*F_ParameterlessFunction)() ;
typedef void (*F_CommandFunction)(ubyte byte) ;

void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command);
#endif

/* free.c */
static F_ParameterlessFunction Init_Lower_Layer = NULL;
static F_CommandFunction Send_Command = NULL;
static ubyte init = 0;
void recieve_value(ubyte my_input)
{
    if(init == 0)
    {
        Init_Lower_Layer();
        init = 1;
    }
    printf("Receiving 0x%02x\n",my_input);
    Send_Command(++my_input);
}

void F_SetupLowerLayer (
    F_ParameterlessFunction initRequest,
    F_CommandFunction sending_command,
    F_CommandFunction *receiving_command)
{
    Init_Lower_Layer = initRequest;
    Send_Command = sending_command;
    *receiving_command = &recieve_value;
}

/* main.c */
int my_hw_do_init()
{
    printf("Doing HW init\n");
    return 0;
}
int my_hw_do_sending(ubyte send_this)
{
    printf("doing HW sending 0x%02x\n",send_this);
    return 0;
}
F_CommandFunction my_hw_send_to_read = NULL;

int main (void)
{
    ubyte rx = 0x40;
    F_SetupLowerLayer(my_hw_do_init,my_hw_do_sending,&my_hw_send_to_read);

    my_hw_send_to_read(rx);
    getchar();
    return 0;
}

4
বিস্তারিত বলার জন্য যত্নশীল, সম্ভবত ব্যবহারিক ব্যবহারের ব্যাখ্যা দিচ্ছেন?
লিওনার্দো হেরেরার

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

0
if(---------)  
printf("hello");  
else   
printf("hi");

শূন্যস্থান পূরণ করুন যাতে হ্যালো বা হাই উভয়ই আউটপুটে উপস্থিত না হয়।
উত্তর:fclose(stdout)


আপনি {}টুলবার বোতামের সাহায্যে কোডটি ফর্ম্যাট করতে পারেন (আমি এটি আপনার জন্য করেছি)। "উদ্ধৃতি" বোতামটি সাদা স্থান রাখে না বা সিনট্যাক্স হাইলাইটিং প্রয়োগ করে না।
vlvaro González
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.