কেন এই কাঠামোর আকার 2 এর পরিবর্তে 3?


91

আমি এই কাঠামোটি সংজ্ঞায়িত করেছি:

typedef struct
{
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col; 

sizeof(col)আমাকে 3 আউটপুট দিতে, কিন্তু না এটি 2 হওয়া উচিত? যদি আমি মাত্র একটি উপাদান মন্তব্য করি তবে sizeofএটি 2 I কেন আমি বুঝতে পারি না: 3 বিটের পাঁচটি উপাদান 15 বিটের সমান এবং এটি 2 বাইটেরও কম।

এটির মতো কোনও কাঠামো সংজ্ঞায়িত করার ক্ষেত্রে কি কোনও "অভ্যন্তরীণ আকার" রয়েছে? আমার কেবল একটি ব্যাখ্যা দরকার, কারণ আমার এ পর্যন্ত ভাষাটি সম্পর্কে ধারণা থেকে আমি 3 টি নয়, 2 বাইটের আকারের প্রত্যাশা করেছি।


4
এটি সম্ভবত প্রান্তিককরণের অনুকূলিতকরণ। এটি একটি নতুন বাইট শুরু করে, যদি পরবর্তী বিট আকারটি প্রকৃত দখলকৃত জায়গায় ফিট না করে।
ῥεῖ

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

4
লক্ষ্য করুন সি যে, গৃহস্থালির কাজ ব্যবহার int- এ ব্যবহার করে, কম পোর্টেবল stackoverflow.com/a/23987436/23118
hlovdal

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

4
বিশেষত, C99 সালে, in6.7.2.1 স্ট্রাক্ট এবং ইউনিয়ন নির্দিষ্টকরণকারী, ¶4 একটি বিট-ফিল্ডের একটি প্রকার থাকবে যা একটি যোগ্য বা অযোগ্য সংস্করণ is_Bool , signed int, unsigned int, অথবা অন্য বাস্তবায়ন-সংজ্ঞায়িত প্রকার। charসুতরাং ব্যবহার করা 'অন্যান্য বাস্তবায়ন-সংজ্ঞায়িত প্রকার' বিভাগে পড়ে।
জোনাথন লেফলার

উত্তর:


95

কারণ আপনি ব্যবহার করছেন char আপনার ক্ষেত্রগুলির জন্য অন্তর্নিহিত ধরণ হিসাবে করছেন, সংকলকটি বাইট দ্বারা গ্রুপ বিট করার চেষ্টা করে এবং যেহেতু এটি প্রতিটি বাইটে আট বিটের বেশি রাখতে পারে না, এটি কেবল প্রতি বাইটে দুটি ক্ষেত্র সংরক্ষণ করতে পারে।

আপনার স্ট্রাক্ট ব্যবহারের বিটগুলির মোট যোগফল 15, সুতরাং সেই পরিমাণের আকারের উপযুক্ত আকারটি একটি হবে short

#include <stdio.h>

typedef struct
{
  char A:3;
  char B:3;
  char C:3;
  char D:3;
  char E:3;
} col; 


typedef struct {
  short A:3;
  short B:3;
  short C:3;
  short D:3;
  short E:3;
} col2; 


int main(){

  printf("size of col: %lu\n", sizeof(col));
  printf("size of col2: %lu\n", sizeof(col2));

}

উপরের কোডটি (আমার মতো -৪-বিট প্ল্যাটফর্মের জন্য) প্রকৃতপক্ষে ফল পাবে 2 জন্য) দ্বিতীয় কাঠামোর জন্য । এ-এর চেয়ে বড় যে কোনও কিছুর জন্য short, কাঠামো ব্যবহৃত ধরণের একের বেশি উপাদান পূরণ করবে না, সুতরাং - একই প্ল্যাটফর্মের জন্য - কাঠামোর আকার চারটির জন্য int, আটটির জন্য longইত্যাদি ইত্যাদি দিয়ে শেষ হবে etc.


4
প্রস্তাবিত কাঠামো সংজ্ঞাটি এখনও ভুল। সঠিক কাঠামো সংজ্ঞাটি 'স্বাক্ষরযুক্ত স্বল্প' ব্যবহার করবে।
ব্যবহারকারী 362929249

21
@ user3629249 স্বাক্ষরযুক্ত স্বল্প 'সঠিক' কেন? যদি ব্যবহারকারী -4 থেকে 3 পর্যন্ত সঞ্চয় করতে চান তবে সংক্ষিপ্তটি সঠিক। যদি ব্যবহারকারী 0 থেকে 7 পর্যন্ত সঞ্চয় করতে চান তবে স্বাক্ষরযুক্ত স্বল্প সংক্ষিপ্তটি সঠিক। মূল প্রশ্নটি একটি স্বাক্ষরিত ধরণের ব্যবহার করে তবে আমি তা বলতে পারি না এটি উদ্দেশ্যমূলক বা দুর্ঘটনাজনক ছিল কিনা।
ব্রুস ডসন

4
বিট বিট charএবং এর মধ্যে পার্থক্য কেন short?
আদা প্লাসপ্লাস প্লাস

4
@ ব্রুসডসন: মানকটি বাস্তবায়নকে charস্বাক্ষরবিহীন হওয়ার অনুমতি দেয় ...
টমাস এডিং

@ থমাসডিং সত্য, মানটি চরটিকে স্বাক্ষরবিহীন হতে দেয়। তবে আমার মূল বক্তব্যটি রয়ে গেছে, স্বাক্ষরযুক্ত স্বাক্ষর করা সঠিক ছিল না দাবি করার জন্য কোনও কারণ দেওয়া হয়নি (যদিও এটি সাধারণত হবে)।
ব্রুস ডসন

78

কারণ আপনার কাছে এমন একটি প্যাকেট ক্ষেত্র নেই যা ন্যূনতম প্রান্তিককরণের সীমানা জুড়ে ছড়িয়ে পড়ে (যা 1 বাইট) তাই তারা সম্ভবত প্যাকটি পাবে

byte 1
  A : 3
  B : 3
  padding : 2
byte 2
  C : 3
  D : 3
  padding : 2
byte 3
  E : 3
  padding : 5

(একই বাইটের ভিতরে ক্ষেত্র / প্যাডিংয়ের ক্রমগুলি ইচ্ছাকৃত নয়, এটি আপনাকে কেবল ধারণা দেওয়ার জন্য, যেহেতু সংকলকটি এটি কীভাবে পছন্দ করে সেগুলি তাদের লিখতে পারে)


16

প্রথম দুটি বিট ক্ষেত্র একক মধ্যে ফিট করে char। তৃতীয়টি এটির সাথে মাপসই করতে পারে না charএবং এর জন্য একটি নতুন প্রয়োজন। 3 + 3 + 3 = 9 যা 8 বিটের চরের সাথে খাপ খায় না।

সুতরাং প্রথম জোড়া একটি নেয় char, দ্বিতীয় জুটি একটি নেয় char, এবং শেষ বিট ক্ষেত্রটি তৃতীয় পায় char


15

বেশিরভাগ সংকলক আপনাকে প্যাডিং নিয়ন্ত্রণ করতে দেয়, যেমন #pragmaএস ব্যবহার করে । এখানে জিসিসি 4.8.1 এর সাথে একটি উদাহরণ রয়েছে:

#include <stdio.h>

typedef struct
{
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col;

#pragma pack(push, 1)
typedef struct {
    char A:3;
    char B:3;
    char C:3;
    char D:3;
    char E:3;
} col2;
#pragma pack(pop)

int main(){
    printf("size of col: %lu\n", sizeof(col));  // 3
    printf("size of col2: %lu\n", sizeof(col2));  // 2
}

নোট করুন যে সংকলকটির ডিফল্ট আচরণ কোনও কারণে রয়েছে এবং সম্ভবত আপনাকে আরও ভাল পারফরম্যান্স দেবে।


9

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

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

unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;

যদি unsigned char8 বিট হয়, সংকলকটির জন্য এই ধরণের চারটি ক্ষেত্র বরাদ্দ করা প্রয়োজন, এবং একটি ব্যতীত সকলকে দুটি বিটফিল্ড বরাদ্দ করতে হবে (যা charতার নিজস্ব ক্ষেত্রে হবে )। যদি সমস্ত charঘোষণাপত্রের সাথে প্রতিস্থাপন করা হয় short, তবে দুটি ধরণের ক্ষেত্র shortথাকবে, যার একটিতে পাঁচটি বিটফিল্ড থাকবে এবং অন্যটি বাকি দুটি ধারণ করবে।

প্রান্তিককরণ বিধিনিষেধ ছাড়াই একটি প্রসেসরে, unsigned shortপ্রথম পাঁচটি ক্ষেত্র এবং unsigned charশেষ দুটি জন্য তিনটি বাইটে সাত তিন বিট ক্ষেত্র সংরক্ষণ করে ডেটা আরও দক্ষতার সাথে নির্ধারণ করা যেতে পারে । তিনটি বাইটে আটটি তিন-বিট ক্ষেত্র সংরক্ষণ করা সম্ভব হওয়া সত্ত্বেও, একটি সংকলক কেবল তখনই অনুমতি দিতে পারত যদি সেখানে তিন-বাইট সংখ্যার টাইপ থাকে যা "বাইরের ক্ষেত্র" প্রকার হিসাবে ব্যবহার করা যেতে পারে।

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

unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;

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


4
বিভিন্ন সংকলক বিট ক্ষেত্রগুলি আলাদাভাবে রাখবেন। আমি ভিজুয়াল সি ++ কীভাবে এটি প্রাসঙ্গিক হতে পারে তার জন্য কিছু ডকুমেন্টেশন লিখেছি। এটি কিছু বিরক্তিকর সমস্যাগুলি নির্দেশ করে
ব্রুস ডসন

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