কি ":-!!" সি কোডে?


1664

আমি /usr/incolve/linux/kernel.h এ এই অদ্ভুত ম্যাক্রো কোডটিতে ঝাঁপিয়ে পড়েছি :

/* Force a compilation error if condition is true, but also produce a
   result (of value 0 and type size_t), so the expression can be used
   e.g. in a structure initializer (or where-ever else comma expressions
   aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

কি করে :-!!?


2
- ইউনারি বিয়োগ <br />! যৌক্তিক নয় <br /> প্রদত্ত পূর্ণসংখ্যার বিপরীত নয় এবং ভেরিয়েবল 0 বা 1 হতে পারে
সিরিলসি

69
গিট দোষ আমাদের জানায় যে স্ট্যাটিক দৃ .়তার এই নির্দিষ্ট ফর্মটি 8c87df4 এ জন বেলিচ দ্বারা প্রবর্তিত হয়েছিল । স্পষ্টতই তাঁর এটি করার ভাল কারণ ছিল (প্রতিশ্রুতি বার্তা দেখুন)।
নিক্লাস বি।

55
@ লন্ডিন: দাবী () কোনও সংকলন-সময় ত্রুটির সৃষ্টি করে না। উপরের নির্মাণের পুরো বিষয়টি এটি।
ক্রিস প্যাসেজো

4
@ গ্রেউকোককোর নিষ্পাপ হবেন না, একজনের পক্ষে সমস্ত কিছু পরিচালনা করার জন্য লিনাক্স খুব বড়। লিনাসের তার লেফটেন্যান্ট রয়েছে এবং তাদের রয়েছে যারা নীচে থেকে পরিবর্তন এবং উন্নতিতে চাপ দিন। লিনাস কেবল সিদ্ধান্ত নিয়েছেন কিনা সে সিদ্ধান্ত নেন তবে তিনি সহকর্মীদের উপর কিছুটা হলেও ভরসা করেন। যদি আপনি ওপেন সোর্স পরিবেশে বিতরণ সিস্টেম কীভাবে কাজ করে সে সম্পর্কে আরও জানতে চান, ইউটিউব ভিডিওটি পরীক্ষা করুন: youtube.com/watch?v=4XpnKHJAok8 (এটি খুব আকর্ষণীয় আলোচনা)।
টমাস প্রুজিনা

3
@ সিপি ক্লাউড, sizeofমানটি নয়, প্রকারটিকে "মূল্যায়ন" করে। এটি প্রকারের ক্ষেত্রে এই ক্ষেত্রে অবৈধ।
উইনস্টন ইওয়ার্ট

উত্তর:


1691

এটি, বাস্তবে, এক্সপ্রেশন ই 0 এবং এটির ব্যর্থতা অবধি মূল্যায়ন করা যায় কিনা তা যাচাই করার একটি উপায়

ম্যাক্রোর কিছুটা ভুল নাম দেওয়া হয়েছে; এটি BUILD_BUG_OR_ZEROবরং আরও ভালো কিছু হওয়া উচিত ...ON_ZERO। ( এটি একটি বিভ্রান্তিমূলক নাম কিনা তা নিয়ে মাঝে মধ্যে আলোচনা হয়েছে ))

আপনার মত প্রকাশটি পড়া উচিত:

sizeof(struct { int: -!!(e); }))
  1. (e): গণনা প্রকাশ e

  2. !!(e): যৌক্তিকভাবে দু'বার উপকার করুন: 0যদি e == 0; অন্যথায় 1

  3. -!!(e): পদক্ষেপ 2 থেকে সংখ্যাটি প্রকাশের সাথে অস্বীকার করুন: 0যদি তা ছিল 0; অন্যথায় -1

  4. struct{int: -!!(0);} --> struct{int: 0;}: যদি এটি শূন্য হয়, তবে আমরা একটি বেনাম পূর্ণসংখ্যার বিটফিল্ডের সাথে একটি কাঠামো ঘোষণা করব যার প্রস্থ শূন্য। সবকিছু ঠিক আছে এবং আমরা স্বাভাবিক হিসাবে এগিয়ে যান।

  5. struct{int: -!!(1);} --> struct{int: -1;}: অন্যদিকে, এটি শূন্য না হলে এটি কিছু নেতিবাচক সংখ্যা হবে will Negative ণাত্মক প্রস্থের সাথে কোনও বিটফিল্ড ঘোষণা করা একটি সংকলন ত্রুটি।

সুতরাং আমরা হয় একটি স্ট্রোকের প্রস্থ 0 বিটফিল্ড দিয়ে বাতাস করব, যা ভাল, বা নেতিবাচক প্রস্থের একটি বিটফিল্ড যা সংকলন ত্রুটি। তারপরে আমরা sizeofসেই ক্ষেত্রটি নিই, সুতরাং আমরা size_tউপযুক্ত প্রস্থের সাথে একটি পাই (যা শূন্যের ক্ষেত্রে eশূন্য হবে)।


কিছু লোক জিজ্ঞাসা করেছেন: কেন কেবল একটি ব্যবহার করবেন না assert?

কিথমোর উত্তর এখানে একটি ভাল সাড়া আছে:

এই ম্যাক্রোগুলি একটি সংকলন-সময় পরীক্ষা প্রয়োগ করে, যদিও দাবি () একটি রান-টাইম পরীক্ষা।

ঠিক তাই. রানটাইমের সময় আপনি আপনার কার্নেলের সমস্যাগুলি সনাক্ত করতে চান না যা আগে ধরা পড়তে পারে! এটি অপারেটিং সিস্টেমের একটি সমালোচনামূলক অংশ। সংকলনের সময় যে পরিমাণে সমস্যা সনাক্ত করা যায়, ততই ভাল।


5
@ ওয়েস্টন বিভিন্ন জায়গায় প্রচুর। নিজের জন্য দেখুন!
জন Feminella

166
সি ++ বা সি স্ট্যান্ডার্ডের সাম্প্রতিক রূপগুলিতে static_assertসম্পর্কিত উদ্দেশ্যে এমন কিছু রয়েছে ।
বেসাইল স্টারিঙ্কেভিচ

54
@ লন্ডিন - # অররের জন্য # লাইন কোডের 3 টি লাইন ব্যবহারের প্রয়োজন হবে যদি # / # ত্রুটি / # শেষ হয়, এবং কেবল প্রাক-প্রসেসরের অ্যাক্সেসযোগ্য মূল্যায়নের জন্য কাজ করবে। এই হ্যাক সংকলক অ্যাক্সেসযোগ্য যে কোনও মূল্যায়নের জন্য কাজ করে।
এড স্টাব

236
লিনাক্স কার্নেল সি ++ ব্যবহার করে না, কমপক্ষে লিনাস জীবিত থাকা অবস্থায় নয়।
মার্ক রান্সম

6
@ ডলডা 2000: " সি-তে বুলিয়ান এক্সপ্রেশনগুলি সর্বদা শূন্য বা একের জন্য মূল্যায়ন করার জন্য সংজ্ঞায়িত করা হয় " - হুবহু নয়। অপারেটার যে ফলন "কথাটি বুলিয়ান" ফলাফল ( !, <, >, <=, >=, ==, !=, &&, ||) সবসময় 0 বা 1. অন্যান্য এক্সপ্রেশন উত্পাদ ফলাফল একটি শর্ত হিসাবে ব্যবহার করা যেতে পারে উত্পাদ পারে, কিন্তু নিছক শূন্য বা নন-জিরো হয়; উদাহরণস্বরূপ, isdigit(c)যেখানে cএকটি অঙ্ক রয়েছে, কোনও শূন্য-মান নির্ধারণ করতে পারে (যা পরে শর্তে সত্য হিসাবে বিবেচিত হয়)।
কিথ থম্পসন

256

:একটি bitfield হয়। হিসাবে !!, এটি যৌক্তিক দ্বিগুণ প্রত্যাখ্যান এবং তাই 0মিথ্যা বা 1সত্যের জন্য প্রত্যাবর্তন । এবং এটি -হ'ল একটি বিয়োগ চিহ্ন, অর্থাত্ গাণিতিক অবহেলা।

অবৈধ ইনপুটগুলিতে সংকলকটি বারফ করার জন্য এটি কেবল একটি কৌশল।

বিবেচনা করুন BUILD_BUG_ON_ZERO। যখন -!!(e)কোনও নেতিবাচক মানকে মূল্যায়ন করা হয়, এটি একটি সংকলন ত্রুটি তৈরি করে। অন্যথায় -!!(e)0 এ মূল্যায়ন করে এবং 0 প্রস্থের বিটফিল্ডটির আকার 0 থাকে And আর তাই ম্যাক্রো size_t0 মান সহ একটিতে মূল্যায়ন করে ।

নামটি আমার দৃষ্টিতে দুর্বল কারণ ইনপুট শূন্য না হলে বাস্তবে বিল্ডটি ব্যর্থ হয়।

BUILD_BUG_ON_NULLখুব অনুরূপ, তবে একটি পরিবর্তে একটি পয়েন্টার দেয় int


14
sizeof(struct { int:0; })কঠোরভাবে মেনে চলছে ?
ওয়াহ

7
সাধারণভাবে ফলাফল হবে কেন 0? একজন structশুধুমাত্র একটি খালি bitfield, সত্য, কিন্তু আমি মনে করি না আকার 0 দিয়ে যে struct অনুমতি দেওয়া হয়। যেমন আপনি যদি এই ধরণের একটি অ্যারে তৈরি করতে চান তবে স্বতন্ত্র অ্যারের উপাদানগুলির এখনও আলাদা ঠিকানা থাকতে হবে, না?
জেনস গুস্ট্ট

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

3
নামহীন শূন্য দৈর্ঘ্য bitfields সংক্রান্ত @ouah, এখানে দেখুন: stackoverflow.com/questions/4297095/...
ডেভিড Heffernan

9
@ ডেভিডহফেরানান আসলে সি 0প্রস্থের অবিস্মরণীয় বিট-ফিল্ডের অনুমতি দেয় , তবে কাঠামোয় নামধারী অন্য কোনও সদস্য না থাকলে তা নয়। (C99, 6.7.2.1p2) "If the struct-declaration-list contains no named members, the behavior is undefined."সুতরাং উদাহরণস্বরূপ sizeof (struct {int a:1; int:0;})কঠোরভাবে মান্য করা হয় তবে তা sizeof(struct { int:0; })হয় না (অপরিবর্তিত আচরণ)।
ওহাহ

168

কিছু লোক মনে হচ্ছে এই ম্যাক্রোগুলিকে বিভ্রান্ত করছে assert()

এই ম্যাক্রোগুলি একটি সংকলন-সময় পরীক্ষা প্রয়োগ করে, যখন assert()একটি রানটাইম পরীক্ষা।


52

ঠিক আছে, আমি যথেষ্ট অবাক হয়েছি যে এই বাক্য গঠনের বিকল্পগুলির উল্লেখ করা হয়নি। অন্য একটি সাধারণ (তবে পুরানো) মেকানিজম হ'ল এমন ফাংশনটি কল করা যা সংজ্ঞায়িত নয় এবং আপনার দৃ as়তা সঠিক হলে ফাংশন কলটি সংকলন করতে অপ্টিমাইজারের উপর নির্ভর করে।

#define MY_COMPILETIME_ASSERT(test)              \
    do {                                         \
        extern void you_did_something_bad(void); \
        if (!(test))                             \
            you_did_something_bad(void);         \
    } while (0)

এই প্রক্রিয়াটি যখন কাজ করে (অপ্টিমাইজেশানগুলি সক্ষম থাকে ততক্ষণ) আপনার লিঙ্ক না করা পর্যন্ত ত্রুটিটি না জানানো এর নেতিবাচক দিক রয়েছে, যে সময়ে আপনি_did_something_bad () ফাংশনের সংজ্ঞাটি খুঁজে পেতে ব্যর্থ হন। এ কারণেই কার্নেল বিকাশকারীরা নেতিবাচক আকারের বিট-ফিল্ড প্রস্থ এবং নেতিবাচক আকারের অ্যারেগুলির (যেমন পরে জিসিসি ৪.৪-এ বিল্ডিং বন্ধ করে দিয়েছিল) কৌশলগুলি ব্যবহার শুরু করে।

সংকলন-সময়ের দাবিগুলির প্রয়োজনীয়তার প্রতি সহানুভূতিতে, জিসিসি 4.3 errorফাংশন বৈশিষ্ট্যটি প্রবর্তন করে যা আপনাকে এই পুরানো ধারণাটি প্রসারিত করতে দেয়, তবে আপনার নির্বাচনের বার্তা সহ একটি সংকলন-সময় ত্রুটি তৈরি করে - আর কোনও গুপ্ত "নেতিবাচক আকারের অ্যারে" না " ভুল বার্তা!

#define MAKE_SURE_THIS_IS_FIVE(number)                          \
    do {                                                        \
        extern void this_isnt_five(void) __attribute__((error(  \
                "I asked for five and you gave me " #number))); \
        if ((number) != 5)                                      \
            this_isnt_five();                                   \
    } while (0)

প্রকৃতপক্ষে, লিনাক্স ৩.৯ হিসাবে, আমাদের এখন একটি ম্যাক্রো বলা হয়েছে compiletime_assertযা এই বৈশিষ্ট্যটি ব্যবহার করে এবং বেশিরভাগ ম্যাক্রোগুলি bug.hসেই অনুযায়ী আপডেট করা হয়েছে। তবুও, এই ম্যাক্রোটি আরম্ভকারী হিসাবে ব্যবহার করা যাবে না। তবে স্টেটমেন্ট এক্সপ্রেশন (অন্য একটি জিসিসির সি-এক্সটেনশন) ব্যবহার করে আপনি পারবেন!

#define ANY_NUMBER_BUT_FIVE(number)                           \
    ({                                                        \
        typeof(number) n = (number);                          \
        extern void this_number_is_five(void) __attribute__(( \
                error("I told you not to give me a five!"))); \
        if (n == 5)                                           \
            this_number_is_five();                            \
        n;                                                    \
    })

এই ম্যাক্রো তার প্যারামিটারটি একবারে মূল্যায়ন করবে (যদি এর পার্শ্ব-প্রতিক্রিয়া থাকে তবে) এবং একটি সংকলন-সময় ত্রুটি তৈরি করবে যা বলেছিল "আমি আপনাকে পাঁচটি না দেওয়ার জন্য বলেছিলাম!" যদি অভিব্যক্তিটি পাঁচটিতে মূল্যায়ন করে বা সংকলন-ধ্রুবক না হয়।

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

আশা করি, জিসি শীঘ্রই এই ত্রুটিগুলি সংশোধন করবে এবং ধ্রুব বিবৃতি প্রকাশকে ধ্রুবক আরম্ভকারী হিসাবে ব্যবহার করার অনুমতি দেবে। এখানে চ্যালেঞ্জটি হ'ল একটি আইনী ধ্রুবক প্রকাশ কী তা নির্ধারণ করে ভাষা নির্দিষ্টকরণ। সি ++ 11 কেবলমাত্র এই ধরণের বা জিনিসের জন্য কনটেক্সারপ কীওয়ার্ড যুক্ত করেছে, তবে সি 11 তে কোনও প্রতিরূপ বিদ্যমান নেই। যদিও সি 11 স্থিতিশীল দাবিগুলি পেয়েছিল, যা এই সমস্যার অংশটি সমাধান করবে, এটি এই সমস্ত ত্রুটিগুলি সমাধান করবে না। সুতরাং আমি আশা করি যে জিসিসি একটি-এক্সটেনশন হিসাবে -std = gnuc99 & -std = gnuc11 বা এরকম কিছু এর মাধ্যমে একটি কনস্টেক্সপ্র্যাপ কার্যকারিতা উপলব্ধ করতে পারে এবং বিবৃতি এক্সপ্রেশন ইত্যাদিতে এর ব্যবহারকে মঞ্জুরি দেয়। অল।


6
আপনার সমস্ত সমাধান বিকল্প নয়। ম্যাক্রোর উপরের মন্তব্যটি বেশ পরিষ্কার " so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren't permitted)." ম্যাক্রো টাইপের একটি অভিব্যক্তি size_t
উইজ

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

যাইহোক আমরা একটি ভেরিয়েবলের জন্য এই ম্যাক্রো ব্যবহার করতে পারি না। ঠিক আছে? error: bit-field ‘<anonymous>’ width not an integer constantএটি কেবল ধ্রুবককে অনুমতি দেয়। তো, এর ব্যবহার কী?
কার্তিক রাজ পালানিচামি

1
@ কার্তিক লিনাক্স কার্নেলের উত্সগুলি কেন ব্যবহার করা হয়েছে তা অনুসন্ধান করুন।
ড্যানিয়েল সান্টোস

@ সুপের্যাট আমি দেখতে পাচ্ছি না যে আপনার মন্তব্য কীভাবে সম্পর্কিত। আপনি কি দয়া করে এটিকে সংশোধন করতে পারেন, আপনি কী বোঝাতে চেয়েছেন বা এটি অপসারণ করতে পারেন?
ড্যানিয়েল সান্টোস

36

0শর্তটি মিথ্যা হলে এটি একটি আকারের বিটফিল্ড তৈরি করে , তবে শর্তটি সত্য / শূন্য না হলে একটি আকার -1( -!!1) বিটফিল্ড। পূর্ববর্তী ক্ষেত্রে, কোনও ত্রুটি নেই এবং স্ট্রাক্টটি কোনও সদস্য সদস্যের সাথে আরম্ভ করা হয়। পরবর্তী ক্ষেত্রে, একটি সংকলন ত্রুটি রয়েছে (এবং -1অবশ্যই আকারের বিটফিল্ড তৈরি করা হয়নি)।


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