সি / সি ++: ফোর্স বিট ফিল্ড অর্ডার এবং প্রান্তিককরণ


87

আমি পড়েছি যে স্ট্রকের মধ্যে বিট ক্ষেত্রগুলির ক্রম প্ল্যাটফর্ম নির্দিষ্ট। আমি যদি বিভিন্ন সংকলক-নির্দিষ্ট প্যাকিং বিকল্পগুলি ব্যবহার করি তবে কী হবে যে এই গ্যারান্টি ডেটাটি লিখিতভাবে যথাযথভাবে সংরক্ষণ করা হবে? উদাহরণ স্বরূপ:

struct Message
{
  unsigned int version : 3;
  unsigned int type : 1;
  unsigned int id : 5;
  unsigned int data : 6;
} __attribute__ ((__packed__));

জিসিসি সংকলক সহ একটি ইন্টেল প্রসেসরে, ক্ষেত্রগুলি মেমোরিতে প্রদর্শিত হয়েছিল যেমন তারা দেখানো হয়েছে। Message.versionবাফারে প্রথম 3 টি বিট ছিল এবং Message.typeতারপরে অনুসরণ করা হয়েছে। যদি আমি বিভিন্ন সংকলকগুলির জন্য সমতুল্য স্ট্রাক প্যাকিংয়ের বিকল্পগুলি পাই তবে এটি কি ক্রস প্ল্যাটফর্ম হবে?


17
যেহেতু একটি বাফার একটি বাইটের সেট, বিট নয়, "বাফারে প্রথম 3 বিট" একটি সুনির্দিষ্ট ধারণা নয়। আপনি কি প্রথম বাইটের 3 সর্বনিম্ন-অর্ডার বিটগুলিকে প্রথম 3 বিট, বা 3 সর্বোচ্চ অর্ডারের বিট হিসাবে বিবেচনা করবেন?
ক্যাফে

4
নেটওয়ার্কে ট্রানজিট করার সময়, "বাফারে প্রথম 3 বিট" খুব ভালভাবে সংজ্ঞায়িত হয়।
জোশুয়া

4
জোশুয়া আইআইআরসি, ইথারনেট প্রথমে প্রতিটি বাইটের সর্বনিম্ন-তাত্পর্যপূর্ণ বিট প্রেরণ করে (যার কারণে ব্রডকাস্ট বিটটি যেখানে রয়েছে)।
টিসি।

আপনি যখন "পোর্টেবল" এবং "ক্রস-প্ল্যাটফর্ম" বলতে চান তবে আপনার অর্থ কী? নির্বাহযোগ্য লক্ষ্যমাত্রা ওএস নির্বিশেষে অর্ডারটি অ্যাক্সেস করতে পারবেন - বা - কোডটি টুলচেন নির্বিশেষে সংকলন করবে?
গ্রেট ক্লোবোন

উত্তর:


103

না, এটি সম্পূর্ণরূপে বহনযোগ্য হবে না। স্ট্রাইকগুলির জন্য প্যাকিং বিকল্পগুলি এক্সটেনশনগুলি এবং এগুলি নিজেরাই পুরোপুরি পোর্টেবল হয় না। এগুলি ছাড়াও, C99 §6.7.2.1, অনুচ্ছেদ 10 বলে: "একটি ইউনিটের মধ্যে বিট-ক্ষেত্র বরাদ্দের ক্রম (উচ্চ-আদেশ থেকে নিম্ন-অর্ডার বা নিম্ন-অর্ডারে নিম্ন-অর্ডার) হ'ল প্রয়োগ-সংজ্ঞায়িত" "

এমনকি একটি একক সংকলক লক্ষ্য প্ল্যাটফর্মের অন্তর্নিহিততার উপর নির্ভর করে বিট ফিল্ডটি আলাদাভাবে বাইরে রাখে।


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

10
কেন সি স্ট্যান্ডার্ড বিট ক্ষেত্রগুলির জন্য কোনও আদেশের গ্যারান্টি দেয়নি?
অ্যারন ক্যাম্পবেল

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

4
বাস্তবায়ন-সংজ্ঞায়িত প্ল্যাটফর্ম-নির্দিষ্ট অপ্টিমাইজেশনের জন্য অনুমতি দেয়। কিছু প্ল্যাটফর্মে, বিট ক্ষেত্রগুলির মধ্যে প্যাডিং অ্যাক্সেসকে উন্নত করতে পারে, 32 বিট ইনটায় চারটি সাত-বিট ক্ষেত্রের কল্পনা করুন: প্রতি 8 ম বিটে এগুলি সারিবদ্ধ করা প্ল্যাটফর্মগুলির জন্য বাইট পড়ার জন্য একটি উল্লেখযোগ্য উন্নতি।
পিটারচেন

নেই packed: ক্রম জোরদার stackoverflow.com/questions/1756811/... বিট ক্রম জোরদার করা কিভাবে: stackoverflow.com/questions/6728218/gcc-compiler-bit-order
সিরো Santilli郝海东冠状病六四事件法轮功

45

বিট ক্ষেত্রগুলি সংকলক থেকে সংকলক পর্যন্ত ব্যাপকভাবে পরিবর্তিত হয়, দুঃখিত।

জিসিসির সাথে, বড় এন্ডিয়ান মেশিনগুলি প্রথমে বিটগুলি বড় প্রান্তটি দেয় এবং ছোট এন্ডিয়ান মেশিনগুলি প্রথমে বিটগুলি সামান্য প্রান্তটি দেয়।

কে অ্যান্ড আর বলছেন "সংলগ্ন [বিট-] কাঠামোর ক্ষেত্রের সদস্যগণ বাস্তবায়ন নির্ভর স্টোরেজ ইউনিটগুলিতে একটি বাস্তবায়ন-নির্ভর পথে পরিচালনা করা হয় When যখন অন্য ক্ষেত্রের নীচের ক্ষেত্রটি উপযুক্ত হবে না ... এটি ইউনিটগুলির মধ্যে বিভক্ত হতে পারে বা ইউনিটটি হতে পারে প্যাডড। প্রস্থের একটি নামবিহীন ক্ষেত্র 0 এই প্যাডিংয়ে বাধ্য করে ... "

অতএব, আপনার যদি মেশিনের স্বাধীন বাইনারি বিন্যাসের প্রয়োজন হয় তবে আপনাকে এটি নিজেই করতে হবে।

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


প্রাক-মানককরণ ছিল এবং সম্ভবত (সম্ভবত আমি ধারণা করি?) বেশিরভাগ ক্ষেত্রেই বরখাস্ত হয়ে গেছে, কে ওআরটি কি সত্যিই একটি দরকারী রেফারেন্স হিসাবে বিবেচিত?
আন্ডারস্কোর_ডে

4
আমার কেএন্ডআর পোস্ট-এএনএসআই।
জোশুয়া

4
এখন তা বিব্রতকর: আমি বুঝতে পারিনি যে তারা এএনএসআই-পরবর্তী একটি সংশোধনী প্রকাশ করেছে। আমার খারাপ!
আন্ডারস্কোর_ডি

35

বিটফিল্ডগুলি এড়ানো উচিত - এমনকি একই প্ল্যাটফর্মের জন্যও তারা সংকলকগুলির মধ্যে খুব বেশি বহনযোগ্য নয়। C99 স্ট্যান্ডার্ড 6.7.2.1/10 থেকে - "স্ট্রাকচার এবং ইউনিয়ন স্পেসিফায়ারস" (C90 স্ট্যান্ডার্ডে একই শব্দ রয়েছে):

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

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

বিটমাস্কগুলি পছন্দ করুন। বিট সেট, সাফ এবং পরীক্ষা করতে ইনলাইনস (বা এমনকি ম্যাক্রো) ব্যবহার করুন।


4
বিটফিল্ডের ক্রম সংকলন সময়ে নির্ধারণ করা যেতে পারে।
গ্রেগ এ উডস

9
এছাড়াও, প্রোগ্রামের বাইরে কোনও বাহ্যিক প্রতিনিধিত্ব না করে বিট ফ্ল্যাগগুলির সাথে ডিল করার সময় বিটফিল্ডগুলি বেশি পছন্দ করে (যেমন ডিস্কে বা রেজিস্টারগুলিতে বা অন্যান্য প্রোগ্রামগুলির দ্বারা অ্যাক্সেস করা মেমরিতে ইত্যাদি)
গ্রেগ এ উডস

4
@ গ্রেগা.উডস: এটি যদি সত্যিই হয় তবে দয়া করে কীভাবে তা বর্ণনা করে একটি উত্তর সরবরাহ করুন। এটির জন্য
গুগল করার

4
@ গ্রেগা.উডস: দুঃখিত, আমি কোন মন্তব্যে উল্লেখ করেছি সে সম্পর্কে লেখা উচিত ছিল। আমার অর্থ: আপনি বলে যে "বিটফিল্ডের ক্রমটি সংকলনের সময় নির্ধারণ করা যেতে পারে"। আমি এটি সম্পর্কে কীভাবে করব এবং কীভাবে করব।
মোজব্বুজ

4
@mozzbozz কটাক্ষপাত আছে planix.com/~woods/projects/wsg2000.c এবং সংজ্ঞা অনুসন্ধান এবং ব্যবহারের _BIT_FIELDS_LTOHএবং_BIT_FIELDS_HTOL
গ্রেগ উ: উডস

11

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

#include <stdio.h>

typedef struct tagT{

    int a:4;
    int b:4;
    int c:8;
    int d:16;
}T;


int main()
{
    char data[]={0x12,0x34,0x56,0x78};
    T *t = (T*)data;
    printf("a =0x%x\n" ,t->a);
    printf("b =0x%x\n" ,t->b);
    printf("c =0x%x\n" ,t->c);
    printf("d =0x%x\n" ,t->d);

    return 0;
}

//- big endian :  mips24k-linux-gcc (GCC) 4.2.3 - big endian
a =0x1
b =0x2
c =0x34
d =0x5678
 1   2   3   4   5   6   7   8
\_/ \_/ \_____/ \_____________/
 a   b     c           d

// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856
 7   8   5   6   3   4   1   2
\_____________/ \_____/ \_/ \_/
       d           c     b   a

6
A এবং b এর আউটপুট নির্দেশ করে যে শেষটি এখনও বিট অর্ডার এবং বাইট অর্ডার সম্পর্কে কথা বলে।
উইন্ডোজ প্রোগ্রামার

বিট অর্ডারিং এবং বাইটের ক্রমান্বয়ে সমস্যাবিজ্ঞানের সাথে দুর্দান্ত উদাহরণ
জনাথন

4
আপনি কি কোডটি কম্পাইল করে চালিত করেছেন? "ক" এবং "বি" এর মানগুলি আমার কাছে যৌক্তিক বলে মনে হয় না: আপনি মূলত বলেই চলেছেন যে সংযোজনকারী শেষের কারণে বাইটের মধ্যে নিবলগুলি অদলবদল করবে। "ডি" এর ক্ষেত্রে, এন্ডিয়ানসগুলি চার অ্যারেগুলির মধ্যে বাইট ক্রমকে প্রভাবিত করবে না (ধরে নেওয়া হচ্ছে চরটি 1 বাইট দীর্ঘ); যদি সংকলক এটি করে, আমরা পয়েন্টার ব্যবহার করে একটি অ্যারের মাধ্যমে পুনরাবৃত্তি করতে সক্ষম হব না। যদি, অন্যদিকে আপনি দুটি 16 বিট পূর্ণসংখ্যার অ্যারে ব্যবহার করেছেন যেমন: uint16 ডেটা [] = x 0x1234,0x5678}; তারপরে অল্প অ্যান্ডিয়ান সিস্টেমে অবশ্যই ডি 0x7856 হবে।
ক্রাউস

6

বেশিরভাগ সময়, সম্ভবত, তবে এটিতে ফার্মটি বাজি ধরবেন না, কারণ আপনি যদি ভুল করেন তবে আপনি বড় হারাবেন।

আপনার যদি সত্যই সত্যই অভিন্ন বাইনারি তথ্য থাকা দরকার, আপনাকে বিটমাস্ক সহ বিটফিল্ড তৈরি করতে হবে - যেমন আপনি বার্তার জন্য স্বাক্ষরযুক্ত স্বল্প (১ bit বিট) ব্যবহার করেন এবং তারপরে তিনটি শীর্ষস্থানীয় বিট উপস্থাপনের জন্য সংস্করণমাস্ক = 0xE000 এর মতো জিনিস তৈরি করুন।

স্ট্রাক্টগুলির মধ্যে প্রান্তিককরণের ক্ষেত্রে একই সমস্যা রয়েছে। উদাহরণস্বরূপ, স্পার্ক, পাওয়ারপিসি এবং 680x0 সিপিইউগুলি সমস্ত বিগ-এন্ডিয়ান এবং স্পার্ক এবং পাওয়ারপিসি সংকলকগুলির জন্য সাধারণ ডিফল্ট হ'ল স্ট্রাক্ট সদস্যদের 4-বাইট সীমানায় সারিবদ্ধ করা। যাইহোক, আমি 680x0 এর জন্য ব্যবহৃত একটি সংকলক কেবল 2-বাইট সীমানায় সংযুক্ত ছিল - এবং প্রান্তিককরণ পরিবর্তন করার কোনও বিকল্প ছিল না!

সুতরাং কিছু স্ট্রাক্টের জন্য, স্পার্ক এবং পাওয়ারপিসিতে আকারগুলি অভিন্ন, তবে 680x0 এ ছোট এবং কিছু সদস্যের কাঠামোর মধ্যে বিভিন্ন মেমরি অফসেট রয়েছে।

এটি যে একটি প্রকল্পে আমি কাজ করেছি তাতে সমস্যা ছিল, কারণ স্পার্কে চলমান একটি সার্ভার প্রক্রিয়া কোনও ক্লায়েন্টকে জিজ্ঞাসা করবে এবং এটি বড়-এন্ডিয়ান ছিল তা আবিষ্কার করবে এবং ধরে নেবে এটি কেবল নেটওয়ার্কে বাইনারি স্ট্রোকগুলি স্কুয়ার্ট করতে পারে এবং ক্লায়েন্টটি মোকাবেলা করতে পারে। এবং এটি পাওয়ারপিসি ক্লায়েন্টদের জন্য দুর্দান্ত কাজ করেছে এবং 680x0 ক্লায়েন্টের সাথে বিগ-টাইম ক্র্যাশ করেছে। আমি কোডটি লিখিনি, এবং সমস্যাটি খুঁজতে বেশ খানিকটা সময় নিয়েছে। তবে একবার করার পরে এটি ঠিক করা সহজ ছিল।


1

আপনার খুব দরকারী মন্তব্য শুরু করার জন্য @ বেনওয়েগ্টকে ধন্যবাদ

না, এগুলি স্মৃতি সংরক্ষণ করার জন্য তৈরি করা হয়েছিল।

লিনাক্স উত্স একটি বাহ্যিক কাঠামোর সাথে মেলে কিছুটা ক্ষেত্র ব্যবহার করে : /usr/incolve/linux/ip.h একটি আইপি ডাটাগ্রামের প্রথম বাইটের জন্য এই কোডটি রয়েছে

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
                version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
        __u8    version:4,
                ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif

তবে আপনার মন্তব্যের আলোকে আমি মাল্টি-বাইট বিট ফিল্ড ফ্রু_অফের জন্য এটির কাজ করার চেষ্টাটি ছেড়ে দিচ্ছি


-9

অবশ্যই সর্বোত্তম উত্তর হ'ল একটি শ্রেণি ব্যবহার করা যা কোনও স্ট্রিম হিসাবে বিট ফিল্ডগুলি পড়েন / লেখেন। সি বিট ফিল্ড স্ট্রাকচার ব্যবহার করা কেবল গ্যারান্টিযুক্ত নয়। রিয়েল ওয়ার্ল্ড কোডিংয়ে এটি ব্যবহার করার জন্য এটি পেশাদারহীন / অলস / বোকা হিসাবে বিবেচনা করা উচিত নয়।


4
আমি মনে করি যে এটি বিট ক্ষেত্রগুলি ব্যবহার করা বোকামি কারণ এটি হার্ডওয়ার রেজিস্ট্রিগুলিকে উপস্থাপনের জন্য একটি খুব পরিষ্কার উপায় সরবরাহ করে যা এটি মডেল হিসাবে তৈরি হয়েছিল, সি
তে

13
@ পরিবর্তন: না, এগুলি মেমরি বাঁচাতে তৈরি করা হয়েছিল। বিটফিল্ডগুলি বাইরের ডেটা স্ট্রাকচারে ম্যাপ করার উদ্দেশ্যে নয় যেমন মেমরি-ম্যাপযুক্ত হার্ডওয়্যার রেজিস্ট্রেশন, নেটওয়ার্ক প্রোটোকল বা ফাইল ফর্ম্যাট। যদি তারা বাইরের ডেটা স্ট্রাকচারে মানচিত্রের উদ্দেশ্যে তৈরি হয়, তবে প্যাকিংয়ের ক্রমটি মানক করা হত।
বেন ভয়েগট

4
বিট ব্যবহার স্মৃতি সাশ্রয় করে। বিট ক্ষেত্রগুলি ব্যবহারের ফলে পাঠযোগ্যতা বৃদ্ধি পায়। কম স্মৃতি ব্যবহার করা দ্রুত হয়। বিটগুলি ব্যবহার করা আরও জটিল পারমাণবিক ক্রিয়াকলাপের অনুমতি দেয়। বাস্তব বিশ্বে অ্যাপ্লিকেশনগুলির মধ্যে কার্য সম্পাদন এবং জটিল পারমাণবিক ক্রিয়াকলাপ প্রয়োজন। এই উত্তরটি আমাদের কাজে আসবে না।
johnnycrash

@ বেনভয়েট সম্ভবত সত্য, তবে কোনও প্রোগ্রামার যদি নিশ্চিত করতে ইচ্ছুক যে তাদের সংকলক / এবিআইয়ের ক্রমটি তাদের প্রয়োজনীয়গুলির সাথে মিলে যায় এবং তদনুসারে তাত্পর্যপূর্ণ বহনযোগ্যতার ত্যাগ করতে পারে - তবে তারা অবশ্যই সেই ভূমিকাটি সম্পাদন করতে পারে । 9 * হিসাবে, "রিয়েল ওয়ার্ল্ড কোডারস" এর কোন প্রামাণিক জনগণ বিটফিল্ডের সমস্ত ব্যবহারকে "পেশাদার / অলস / বোকা" হিসাবে বিবেচনা করে এবং তারা এটিকে কোথায় বলেছে?
আন্ডারস্কোর_ডে

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