আমি কীভাবে একটি প্রিপ্রসেসর ম্যাক্রোতে "মাপের" ব্যবহার করতে পারি?


95

sizeofপ্রিপ্রসেসর ম্যাক্রোতে কী কোনও উপায় আছে ?

উদাহরণস্বরূপ, কয়েক বছর ধরে আমি এমন কিছু করতে চেয়েছিলাম এমন একটি পরিস্থিতি রয়েছে:

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

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

বলা বাহুল্য - আমি sizeofউপরে বর্ণিত পদ্ধতিতে কোনওটি ব্যবহার করতে সক্ষম হবে বলে মনে হয় না ।


বিল্ড সিস্টেমের অস্তিত্বের সঠিক কারণ এটি।
আইমন

4
এই কারণেই # অস্থির নির্দেশাবলী সর্বদা ডাবল উক্তিতে থাকা উচিত ("না" এর কারণে নিরবচ্ছিন্ন চরিত্রটি স্থির থাকে)।
জেনস

4
হ্যালো @ ব্র্যাড অনুগ্রহ করে আপনার গ্রহণযোগ্য উত্তরগুলি কিছুই মনে রাখার উত্তরের পরিবর্তনের জন্য বিবেচনা করুন, কারণ মাঝামাঝি সময়ে, বর্তমানে গৃহীত উত্তরটি কিছুটা অচল হয়ে গেছে।
বোডো থিয়েসন

@ বোডো থিসেন সম্পন্ন
ব্র্যাড

উত্তর:


71

এই কাজ করার বিভিন্ন উপায় আছে। নীচের স্নিপেটগুলি sizeof(someThing)সমান হলে কোনও কোড তৈরি করবে না PAGE_SIZE; অন্যথায় তারা একটি সংকলন-সময় ত্রুটি উত্পাদন করবে।

1. সি 11 উপায়

সি 11 দিয়ে শুরু করে আপনি ব্যবহার করতে পারেন static_assert(প্রয়োজনীয় #include <assert.h>)।

ব্যবহার:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2. কাস্টম ম্যাক্রো

আপনি যখন sizeof(something)প্রত্যাশা করেন না তা যদি আপনি কেবল একটি সংকলন-সময় ত্রুটি পেতে চান তবে আপনি নিম্নলিখিত ম্যাক্রোটি ব্যবহার করতে পারেন:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

ব্যবহার:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

এই নিবন্ধটি কেন এটি কাজ করে তা বিশদে ব্যাখ্যা করে।

৩. এমএস-নির্দিষ্ট

মাইক্রোসফ্ট সি ++ সংকলকটিতে আপনি C_ASSERT ম্যাক্রো (প্রয়োজনীয় #include <windows.h>) ব্যবহার করতে পারেন , যা বিভাগ 2 এ বর্ণিতটির অনুরূপ একটি কৌশল ব্যবহার করে।

ব্যবহার:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);

4
...এটা পাগলামি. @ ব্র্যাড (ওপি) কেন এটি গৃহীত উত্তর নয়?
ইঞ্জিনিয়ার

BUILD_BUG_ON এর জন্য দুর্দান্ত রেফারেন্স।
পেট্রা ভেপেক

4
ম্যাক্রো gccজিএনইউতে কাজ করে না (ভার্সন ৪.৮.৪ এ পরীক্ষিত) (লিনাক্স)। এ ((void)sizeof(...সঙ্গে করে ত্রুটির expected identifier or '(' before 'void'এবং expected ')' before 'sizeof'। কিন্তু নীতিগতভাবে size_t x = (sizeof(...পরিবর্তে ইচ্ছাকৃতভাবে কাজ করে। আপনাকে কোনওভাবে ফলাফলটি "ব্যবহার" করতে হবে। এটি কোনও ফাংশনের অভ্যন্তরে বা বৈশ্বিক সুযোগে একাধিকবার বলা হওয়ার জন্য , এর মতো কিছু extern char _BUILD_BUG_ON_ [ (sizeof(...) ];বারবার ব্যবহার করা যেতে পারে (কোনও পার্শ্ব-প্রতিক্রিয়া নেই, আসলে _BUILD_BUG_ON_কোথাও উল্লেখ করা যায় না)।
জোনব্রেভ

২০১১ সাল থেকে অনেক বেশি সময় ধরে স্ট্যাটিক অ্যাসেসর্ট ব্যবহার করা হয়েছে a
ড্যান

4
@ ইঞ্জিনিয়ার চেহারা, উন্মাদনা থেমে গেছে;)
বোডো থিয়েসন

71

sizeofপ্রি-প্রসেসর ম্যাক্রোতে কোনও " " ব্যবহার করার উপায় আছে কি ?

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

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

তবে সি তে সংকলন-সময় জোর পাওয়ার কৌশল রয়েছে (উদাহরণস্বরূপ, এই পৃষ্ঠাটি দেখুন )।


দুর্দান্ত নিবন্ধ - চতুর সমাধান! যদিও আপনাকে অ্যাডমিন করতে হবে - এটিকে কাজ করার জন্য তারা সত্যিকার অর্থে সি বাক্য গঠনকে সীমাতে ঠেলে দিয়েছে! : -ও
ব্র্যাড

4
পরিণত হয়েছে - যেমন নিবন্ধটি বলেছে - আমি এখনই লিনাক্স কার্নেল কোডটি তৈরি করছি - এবং কার্নেলের মধ্যে ইতিমধ্যে একটি সংজ্ঞা রয়েছে - BUILD_BUGटका - যেখানে কার্নেল এটির মতো জিনিসগুলির জন্য ব্যবহার করে: BUILD_BUGटका (আকারের (চর)! = 8)
ব্র্যাড

4
@ ব্র্যাড BUILD_BUG_ON এবং অন্যরা নিশ্চয়ই-ভুল কোড উত্পন্ন করছে যা সংকলন করতে ব্যর্থ হবে (এবং প্রক্রিয়াতে কিছু অ-সুস্পষ্ট ত্রুটি বার্তা দেবে)। সত্যিই #if বিবৃতি নয়, সুতরাং আপনি উদাহরণস্বরূপ এর ভিত্তিতে কোডের ব্লককে বাদ দিতে পারবেন না।
কেল্টার

10

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

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

//Check overall structure size
typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1];

//check 8 byte alignment for flash write or similar
typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1];

//check offset in structure to ensure a piece didn't move
typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];

এটি আসলে একটি স্ট্যান্ডার্ড সি প্রকল্পের জন্য খুব ভাল কাজ করে ... আমি এটি পছন্দ করি!
অ্যাশলে ডানকান

4
শূন্য বরাদ্দের কারণে এটির সঠিক উত্তর হওয়া উচিত। একটি সংজ্ঞায়িত করার চেয়ে আরও ভাল:#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
রেনাড সেরাতো

p__line__ কোনও অনন্য নাম তৈরি করে না। এটি ভেরিয়েবল হিসাবে p__LINE__ উত্পাদন করে। আপনার একটি প্রিপ্রোক ম্যাক্রোর প্রয়োজন হবে এবং sys / cdefs.h থেকে __CONCAT ব্যবহার করুন।
করুস

9

আমি জানি এই থ্রেডটি আসলেই পুরানো তবে ...

আমার সমাধান:

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

যতক্ষণ এই অভিব্যক্তিটি শূন্যের সমান হয়, ততক্ষণ তা সূক্ষ্ম সংকলন করে। অন্য কিছু এবং এটি ঠিক সেখানেই ফুঁসে উঠেছে। কারণ পরিবর্তনশীল বাহ্যিকভাবে এটি কোনও স্থান গ্রহণ করবে না, এবং যতক্ষণ না কেউ এটি উল্লেখ না করে (যা তারা করবে না) এটি কোনও লিঙ্ক ত্রুটির কারণ হতে পারে না।

দৃsert় ম্যাক্রোর মতো নমনীয় নয়, তবে আমার জিসিসির সংস্করণটি সংকলন করতে আমি এটি পেতে পারি নি এবং এটি করবে ... এবং আমি মনে করি এটি প্রায় কোথাও সংকলিত হবে।


6
দুটি আন্ডারস্কোর দিয়ে শুরু করে নিজের ম্যাক্রোগুলি কখনও আবিষ্কার করবেন না । এই পথটি উন্মাদনা (ওরফে অপরিজ্ঞাত আচরণ ) lies
জেনস


আর্ম জিসিসি সংকলক দিয়ে সংকলিত হলে কাজ করে না। প্রত্যাশিত ত্রুটিটি দেয় "ত্রুটি: ফাইল স্কোপে ' চেক ' পরিবর্তনশীল "
বজ্রবৃদ্ধি

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

4

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

নিজেকে একটু সি প্রোগ্রাম লিখুন:

/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* 'int' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }

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

sizeof_int = `./sizeof_int`
File.open('include/sizes.h','w') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER

তারপরে আপনার মেকফিল বা অন্য বিল্ড স্ক্রিপ্টে একটি বিধি যুক্ত করুন, যা এটি উপরের স্ক্রিপ্টটি তৈরি করতে চালিত করবে sizes.h

sizes.hআকারগুলির উপর ভিত্তি করে প্রিপ্রসেসর শর্তাদি যেখানেই আপনার প্রয়োজন সেখানে অন্তর্ভুক্ত করুন ।

সম্পন্ন!

(আপনি কি কখনও ./configure && makeকোনও প্রোগ্রাম বানাতে টাইপ করেছেন ? configureস্ক্রিপ্টগুলি কি মূলত উপরের মতো হয় ...)


আপনি যখন "অটোকনফ" এর মতো সরঞ্জাম ব্যবহার করছেন তখন এটি একইরকম জিনিস।
আলেকজান্ডার স্টোহর

4

পরবর্তী ম্যাক্রো সম্পর্কে কি:

/* 
 * Simple compile time assertion.
 * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
 */
#define CT_ASSERT(exp, message_identifier) \
    struct compile_time_assertion { \
        char message_identifier : 8 + !(exp); \
    }

উদাহরণস্বরূপ মন্তব্যে এমএসভিসি এমন কিছু বলে:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits

4
এটি প্রশ্নের কোনও উত্তর নয় কারণ আপনি এটি কোনও #ifপূর্বনির্ধারকের নির্দেশিকায় ব্যবহার করতে পারবেন না ।
মাস্টার -

1

এই আলোচনার জন্য কেবল একটি রেফারেন্স হিসাবে, আমি প্রতিবেদন করি যে কিছু সংকলক প্রি-প্রসেসরের সময় আকারের (আকার) পান।

জেমস এমসিএনেলিস উত্তরটি সঠিক, তবে কিছু সংকলক এই সীমাবদ্ধতার মধ্য দিয়ে যায় (এটি সম্ভবত কঠোর আনসিস সি লঙ্ঘন করে)।

এর একটি কেস হিসাবে, আমি আইআর সি-সংকলক (সম্ভবত পেশাদার মাইক্রোকন্ট্রোলার / এমবেডেড প্রোগ্রামিংয়ের ক্ষেত্রে নেতৃস্থানীয়) উল্লেখ করি।


আপনি কি এ ব্যাপারে নিশ্চিত? আইএআর দাবি করেছে যে তাদের সংকলকগুলি আইএসও সি 90 এবং সি 99 মানের সাথে খাপ খায়, যা sizeofপ্রিপ্রসেসিংয়ের সময় মূল্যায়নের অনুমতি দেয় না । sizeofকেবল সনাক্তকারী হিসাবে বিবেচনা করা উচিত।
কিথ থম্পসন

6
১৯৯৯ সালে, কমপ্লেক্স.ডি.ডি.সি. নিউজগ্রুপের একজন লিখেছেন: "সেই দিনগুলিতে খুব ভাল লাগল যখন #if (sizeof(int) == 8)বাস্তবে কাজ করা (কিছু সংকলকগুলিতে) ছিল।" প্রতিক্রিয়া: "অবশ্যই আমার সময়ের আগে হওয়া উচিত ছিল" ", ডেনিস রিচি থেকে এসেছিলেন।
কিথ থম্পসন

দেরিতে জবাবের জন্য দুঃখিত ... হ্যাঁ, আমি নিশ্চিত, আমার কাছে 8/16/32 বিট মাইক্রোকন্ট্রোলার, রেনেসাস সংকলক (আর 8 এবং আরএক্স উভয়) এর জন্য সংকলিত কোডের উদাহরণ রয়েছে।
গ্রাজিয়ানো গভর্নর

আসলে, "কঠোর" আইএসও সি প্রয়োজনের জন্য কিছু বিকল্প থাকতে হবে
গ্রাজিয়ানো গভর্নিটার

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

1

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x)) কাজ করতেও পারে


এটি একটি আকর্ষণীয় সমাধান তবে এটি কেবল সংজ্ঞায়িত ভেরিয়েবলগুলির সাথে কাজ করে, প্রকারের সাথে নয়। ভেরিয়েবলগুলির সাথে নয় তবে প্রকারের সাথে কাজ করে এমন আরও একটি সমাধান #define SIZEOF_TYPE(x) (((x*)0) + 1)
হ'ল

7
এটি কাজ করে না কারণ আপনি এখনও তার ফলাফলটি একটি #ifশর্তের মধ্যে ব্যবহার করতে পারবেন না । এটি কোনও লাভ দেয় না sizeof(x)
ইন্টারজয়

1

সি 11-এ _Static_assertকীওয়ার্ড যুক্ত হয়েছে। এটি ব্যবহার করা যেতে পারে:

_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")

0

আমার পোর্টেবল সি ++ কোডে ( http://www.starmessagesoftware.com/cpcclibrary/ ) আমার কিছু স্ট্রাক্ট বা ক্লাসের আকারগুলিতে একটি নিরাপদ প্রহরী রাখতে চেয়েছিল।

প্রিপ্রসেসরটি কোনও ত্রুটি নিক্ষেপ করার উপায় খুঁজে বের করার পরিবর্তে (যা এখানে বলা হয়েছে আকারের () এর সাথে কাজ করতে পারে না), আমি এখানে একটি সমাধান পেয়েছি যার ফলে সংকলক ত্রুটি ছুঁড়েছে causes http://www.barrgroup.com/ এম্বেডড- সিস্টেমস / হাও- টো / সি- ফিক্সড- প্রস্থ-Integers-C99

আমার কোডারটিকে (এক্সকোড) কোনও ত্রুটি ছুঁড়ে ফেলার জন্য আমাকে সেই কোডটি মানিয়ে নিতে হয়েছিল:

static union
{
    char   int8_t_incorrect[sizeof(  int8_t) == 1 ? 1: -1];
    char  uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
    char  int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
    char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
    char  int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
    char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};

4
আপনি কি নিশ্চিত যে সেই "−1" কখনই 0xFFFF… FF হিসাবে ব্যাখ্যা করা হবে না, যা আপনার প্রোগ্রামকে সমস্ত ঠিকানাযোগ্য মেমরির জন্য অনুরোধ করে?
আন্তন স্যামসনভ

0

উল্লিখিত ম্যাক্রোগুলি চেষ্টা করার পরে, এই টুকরাটি পছন্দসই ফলাফলটি বলে মনে হচ্ছে ( t.h):

#include <sys/cdefs.h>
#define STATIC_ASSERT(condition) typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(int) == 42);

চলমান cc -E t.h:

# 1 "t.h"
...
# 2 "t.h" 2

typedef char _static_assert_3[ (sizeof(int) == 4) ? 1 : -1];
typedef char _static_assert_4[ (sizeof(int) == 42) ? 1 : -1];

চলমান cc -o t.o t.h:

% cc -o t.o t.h
t.h:4:1: error: '_static_assert_4' declared as an array with a negative size
STATIC_ASSERT(sizeof(int) == 42);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.h:2:84: note: expanded from macro 'STATIC_ASSERT'
  ...typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
                                                       ^~~~~~~~~~~~~~~~~~~~
1 error generated.

42 সবকিছুর উত্তর নেই ...


0

সংকলন সময়ে পরীক্ষা করার জন্য তাদের সীমাবদ্ধতার বিরুদ্ধে ডেটা স্ট্রাকচারের আকার আমি এই কৌশলটি ব্যবহার করেছি।

#if defined(__GNUC__)
{ char c1[sizeof(x)-MAX_SIZEOF_X-1]; } // brakets limit c1's scope
#else
{ char c1[sizeof(x)-MAX_SIZEOF_X]; }   
#endif

যদি x এর আকার তার সীমা MAX_SIZEOF_X এর চেয়ে বড় বা সমান হয় তবে জিসিসি উইল একটি 'অ্যারের আকার খুব বড় "ত্রুটির সাথে অভিযোগ করে। ভিসি ++ ত্রুটি C2148 কে প্রকাশ করবে ('অ্যারের মোট আকার 0x7fffffff বাইটের বেশি হওয়া উচিত নয়') বা C4266 'ধ্রুব আকার 0 এর অ্যারে বরাদ্দ করতে পারে না।

দুটি সংজ্ঞা প্রয়োজন কারণ জিসিসি একটি শূন্য আকারের অ্যারেটিকে এভাবে সংজ্ঞায়িত করতে দেয় (আকারের x - n))


-10

sizeofঅপারেটর প্রাক প্রসেসর জন্য উপলব্ধ নেই, কিন্তু আপনি হস্তান্তর করতে পারেন sizeofকম্পাইলার এবং রানটাইম মধ্যে শর্ত চেক করুন:

#define elem_t double

#define compiler_size(x) sizeof(x)

elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
    printf("%d",(int)n);
} else {
    printf("%lf",(double)n);
}

13
ইতিমধ্যে গৃহীত উত্তরে কীভাবে এটি উন্নতি হয়? সংজ্ঞাটি কোন উদ্দেশ্যটি compiler_sizeপরিবেশন করে? আপনার উদাহরণটি কী দেখানোর চেষ্টা করে?
ugoren
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.