কেন একটি বিট ক্ষেত্রের জন্য একটি মান নির্ধারণ করা একই মানটি ফেরত দিচ্ছে না?


96

আমি এই কোওরা পোস্টে নীচের কোডটি দেখেছি :

#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
  struct mystruct s;
  s.enabled = 1;
  if(s.enabled == 1)
    printf("Is enabled\n"); // --> we think this to be printed
  else
    printf("Is disabled !!\n");
}

সি এবং সি ++ উভয় ক্ষেত্রেই কোডের আউটপুটটি অপ্রত্যাশিত ,

নিষ্ক্রিয় করা !!

যদিও "সাইন বিট" সম্পর্কিত ব্যাখ্যা সেই পোস্টে দেওয়া হয়েছে, আমি বুঝতে অক্ষম, এটি কীভাবে সম্ভব যে আমরা কোনও কিছু সেট করি এবং তারপরে এটি যেমন হয় তেমন প্রতিফলিত হয় না।

কেউ আরও বিশদ ব্যাখ্যা দিতে পারেন?


বিঃদ্রঃ : উভয় ট্যাগ & প্রয়োজনীয়, কারণ বিট-ক্ষেত্রগুলি বর্ণনা করার জন্য তাদের মান কিছুটা পৃথক। সি স্পেসিফিকেশন এবং সি ++ নির্দিষ্টকরণের জন্য উত্তরগুলি দেখুন ।


46
যেহেতু বিটফিল্ড হিসাবে ঘোষিত হয়েছে বলে intআমি মনে করি এটি কেবল মানগুলি ধরে রাখতে পারে 0এবং -1
ওসিরিস

6
এটি কীভাবে int -1 সঞ্চয় করে তা ভেবে দেখুন। সমস্ত বিট 1 সেট করা আছে। অতএব, আপনার যদি কেবল একটি বিট থাকে তবে এটি স্পষ্টভাবে -1 হতে হবে। সুতরাং 1 বিট ইন 1 এবং -1 একই হয়। চেকটি 'if (s.en सक्षम! = 0)' এ পরিবর্তন করুন এবং এটি কার্যকর হয়। কারণ 0 এটি হতে পারে না।
জর্জেন

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

8
আপনি কি এটিতে পরিবর্তন করার চেষ্টা করেছেন struct mystruct { unsigned int enabled:1; };?
চ্যাটারঅন

4
দয়া করে সি এবং সি ++ ট্যাগ নীতিগুলি পড়ুন , বিশেষ করে ক্রস-ট্যাগিং সি এবং সি ++ উভয় সম্পর্কিত অংশটি এখানে সম্প্রদায়ের sensকমত্যের মাধ্যমে প্রতিষ্ঠিত । আমি কিছু রোলব্যাক যুদ্ধে যাচ্ছি না, তবে এই প্রশ্নটিকে ভুলভাবে সি ++ ট্যাগ করা হয়েছে। এমনকি বিভিন্ন টিসির কারণে যদি ভাষাগুলির মধ্যে কিছুটা পার্থক্য থাকে তবে সি এবং সি ++ এর মধ্যে পার্থক্য সম্পর্কে আলাদা প্রশ্ন করুন make
লন্ডিন

উত্তর:


78

বিট ক্ষেত্রগুলি মান দ্বারা অবিশ্বাস্যভাবে দুর্বল সংজ্ঞাযুক্ত। এই কোডটি দেওয়া হয়েছে struct mystruct {int enabled:1;};, তবে আমরা জানি না :

  • এটি কতটা জায়গা দখল করে - যদি প্যাডিং বিট / বাইট থাকে এবং তারা মেমোরিতে কোথায় থাকে।
  • যেখানে বিটটি স্মৃতিতে অবস্থিত। সংজ্ঞায়িত করা হয় না এবং এটি চূড়ান্ততার উপরও নির্ভর করে।
  • int:nবিটফিল্ডটি স্বাক্ষরিত বা স্বাক্ষরবিহীন হিসাবে বিবেচিত হবে কিনা ।

শেষ অংশটি সম্পর্কে, C17 6.7.2.1/10 বলেছেন:

একটি বিট-ফিল্ডটি সাইন ইন বা স্বাক্ষরযুক্ত পূর্ণসংখ্যার ধরণের নির্দিষ্ট বিটগুলির সমন্বয়ে 125 হিসাবে সংজ্ঞায়িত হয় )

উপরোক্ত ব্যাখ্যা করে অ-আদর্শিক নোট:

125) উপরে 7.7.২ তে উল্লিখিত হিসাবে, ব্যবহৃত প্রকৃত ধরণের স্পেসিফায়ার intবা টাইপডেফ-নাম হিসাবে intসংজ্ঞায়িত হলে বিট-ফিল্ডটি স্বাক্ষরিত বা স্বাক্ষরযুক্ত কিনা তা বাস্তবায়ন-সংজ্ঞায়িত।

যদি বিটফিল্ডটিকে বিবেচনা করা হয় signed intএবং আপনি কিছুটা আকার তৈরি করেন 1, তবে কেবলমাত্র সাইন বিটের জন্য ডেটার কোনও স্থান নেই। এই কারণেই আপনার প্রোগ্রামটি কিছু সংকলকগুলিতে অদ্ভুত ফলাফল দিতে পারে।

ভালো অনুশীলন:

  • বিট-ফিল্ড কখনও কোনও কাজে ব্যবহার করবেন না।
  • intকোনও ধরণের বিট ম্যানিপুলেশনের জন্য স্বাক্ষরিত প্রকারের ব্যবহার এড়িয়ে চলুন ।

5
কর্মক্ষেত্রে আমাদের বিটফিল্ডগুলির প্যাড না রয়েছে তা নিশ্চিত করার জন্য আকার এবং ঠিকানার উপরে স্ট্যাটিক_সেসার্ট রয়েছে। আমরা আমাদের ফার্মওয়্যারগুলিতে হার্ডওয়্যার রেজিস্টারগুলির জন্য বিটফিল্ড ব্যবহার করি।
মাইকেল

4
@ লন্ডিন: # সংজ্ঞায়িত-মুখোশ এবং অফসেটের সাথে কুৎসিত জিনিসটি হ'ল আপনার কোডটি শিফট এবং বিট-ওয়াইজ এবং / অথবা অপারেটরগুলির সাথে ছড়িয়ে পড়ে। বিটফিল্ড সহ সংকলক আপনার জন্য এটি যত্ন করে।
মাইকেল

4
@Michael সঙ্গে bitfields কম্পাইলার আপনার জন্য যে যত্ন নেয়। ঠিক আছে, যদি আপনার "মানদণ্ডগুলি" "নন-পোর্টেবল" এবং "অপ্রত্যাশিত" হয় তবে তা ঠিক আছে। আমার চেয়ে উঁচু।
অ্যান্ড্রু হেনেল

4
@ অ্যান্ড্রুহেনেল লুশেনকো বলছেন যে কেবল সি স্ট্যান্ডার্ডের দৃষ্টিকোণ থেকে , এটি x86-64 এবিআই অনুসরণ করতে বা বেছে নেবে কিনা তা বাস্তবায়নের উপর নির্ভর করে ।
mtraceur

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

58

আমি বুঝতে অক্ষম, এটি কীভাবে সম্ভব যে আমরা কোনও কিছু সেট করি এবং তারপরে এটি যেমন প্রদর্শিত হয় না তেমন হয়।

আপনি জিজ্ঞাসা করছেন কেন এটি বনাম সংকলন করে আপনাকে ত্রুটি দেয়?

হ্যাঁ, এটি আদর্শভাবে আপনাকে একটি ত্রুটি দেওয়া উচিত। এবং এটি করে, যদি আপনি আপনার সংকলকের সতর্কতা ব্যবহার করেন। জিসিসিতে, এর সাথে -Werror -Wall -pedantic:

main.cpp: In function 'int main()':
main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1' 
changes value from '1' to '-1' [-Werror=overflow]
   s.enabled = 1;
           ^

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

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

(টিএল; ডিআর - আপনি যদি বিট-ফিল্ডগুলিকে বৈধভাবে "প্রয়োজন" হিসাবে যথেষ্ট পরিশীলিত হন তবে সেগুলি আপনাকে পরিবেশন করার জন্য যথেষ্ট সংজ্ঞাযুক্ত নয়))


15
বিট-ফিল্ড অধ্যায়টি যেদিন ডিজাইন করা হয়েছিল, সেই দিনটির লেখকরা ছুটিতে ছিলেন on সুতরাং দরজার এটি করতে হয়েছিল। সেখানে সম্পর্কে কোন যুক্তিপূর্ণ হয় কিছু সংক্রান্ত কিভাবে বিট-ক্ষেত্র ডিজাইন করা হয়।
লন্ডিন

9
কোনও সুসংগত প্রযুক্তিগত যুক্তি নেই। তবে এটি আমাকে এই সিদ্ধান্তে পৌঁছে দেয় যে এখানে একটি রাজনৈতিক যুক্তি ছিল: বিদ্যমান কোড বা বাস্তবায়নগুলির কোনওটিকে ভুল না করে এড়াতে। তবে ফলাফলটি হ'ল বিটফিল্ডগুলির বিষয়ে খুব কমই রয়েছে যার উপর আপনি নির্ভর করতে পারেন।
জন বলিঞ্জার

6
@ জনবোলিঞ্জার অবশ্যই রাজনীতি করেছিলেন সেখানে সি 90 এর প্রচুর ক্ষতি হয়েছিল। আমি একবার কমিটির একজন সদস্যের সাথে কথা বলেছিলাম যারা প্রচুর কচুর উত্সের ব্যাখ্যা দিয়েছিল - আইএসও স্ট্যান্ডার্ডকে কিছু বিদ্যমান প্রযুক্তির পক্ষে যাওয়ার অনুমতি দেওয়া যায় না। এ কারণেই আমরা মোরোনিক বিষয়গুলির সাথে আটকে আছি যেমন 1 এর পরিপূরক এবং স্বাক্ষরযুক্ত বিশালতার charপক্ষে সমর্থন , প্রয়োগ-সংজ্ঞায়িত স্বাক্ষর, 8 বিট নয় এমন বাইটগুলির পক্ষে সমর্থন ইত্যাদি They তাদের মরোনিক কম্পিউটারগুলিকে বাজারের অসুবিধা দেওয়ার অনুমতি দেওয়া হয়নি।
লন্ডিন

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

4
এটি এখনও পয়েন্ট নং হিসাবে তালিকাভুক্ত করা হয়। সি 2 এক্স সনদে সি এর মূল নীতিগুলির 1: "বিদ্যমান কোডটি গুরুত্বপূর্ণ, বিদ্যমান বাস্তবায়নগুলি নয়।" ... "কারও বাস্তবায়ন উদাহরণ হিসাবে ধরা হয় নি যার মাধ্যমে সি সংজ্ঞায়িত করা হবে: ধারণা করা হয় যে বিদ্যমান সমস্ত বাস্তবায়ন অবশ্যই মানের সাথে সামঞ্জস্য করতে কিছুটা পরিবর্তন করতে হবে।"
লুশেনকো

23

এটি বাস্তবায়ন সংজ্ঞায়িত আচরণ। আমি এই ধারণাটি তৈরি করছি যে আপনি যে মেশিনগুলি চালাচ্ছেন এটি দ্বিগুণ-প্রশংসা স্বাক্ষরিত পূর্ণসংখ্যা ব্যবহার করে intএবং যদি এই বিবৃতিটির সত্যিকারের অংশ হয় তবে আপনি কেন প্রবেশ করেন না তা ব্যাখ্যা করার জন্য এই ক্ষেত্রে একটি স্বাক্ষরযুক্ত পূর্ণসংখ্যা হিসাবে বিবেচনা করবেন।

struct mystruct { int enabled:1; };

enable1 বিট বিট-ফিল্ড হিসাবে ঘোষণা করে । যেহেতু এটি স্বাক্ষরিত, বৈধ মানগুলি -1এবং 0। ফিল্ডটি 1ওভারফ্লোগুলিতে সেট করা যা সেই বিটটিতে ফিরে যাবে-1 (এটি পূর্বনির্ধারিত আচরণ)

মূলত একটি স্বাক্ষরিত বিট-ফিল্ডের সাথে ডিল করার সময় সর্বাধিক মানটি 2^(bits - 1) - 1যা 0এই ক্ষেত্রে।


"এটি স্বাক্ষরিত ইনসে, বৈধ মানগুলি -1 এবং 0"। কে বলেছে এটি স্বাক্ষরিত? এটি সংজ্ঞায়িত নয় তবে বাস্তবায়ন-সংজ্ঞায়িত আচরণ। যদি এটি স্বাক্ষরিত হয়, তবে বৈধ মানগুলি হয় -এবং +। 2 এর পরিপূরক কোন ব্যাপার না।
লন্ডিন

5
@ লন্ডিন এ 1 বিট দ্বিগুণ প্রশংসা সংখ্যার কেবল দুটি সম্ভাব্য মান রয়েছে। যদি বিটটি সেট করা থাকে, তবে এটি যেহেতু সাইন বিট, এটি -1 হয়। যদি এটি সেট না করা থাকে তবে এটি "ইতিবাচক" 0. আমি জানি এটি বাস্তবায়ন সংজ্ঞায়িত, আমি কেবল সর্বাধিক সাধারণ রোপন ব্যবহার করে ফলাফলগুলি ব্যাখ্যা করছি
নাথান অলিভার

4
এখানে মূল কীটি হ'ল 2 এর পরিপূরক বা অন্য কোনও স্বাক্ষরিত ফর্ম একক বিট উপলভ্য হয়ে কাজ করতে পারে না।
লন্ডিন

4
@ জনবোলিংগার আমি এটি বুঝতে পারি। এই কারণেই আমার অস্বীকার আছে যে এটি বাস্তবায়িত সংজ্ঞায়িত। কমপক্ষে বড় 3 এর জন্য তারা সকলেই intএই ক্ষেত্রে স্বাক্ষরিত হিসাবে আচরণ করে । এটি লজ্জার বিষয় যে বিট-ফিল্ডগুলি এত নির্দিষ্ট করে দেওয়া হয়েছে। এটি মূলত এখানে এই বৈশিষ্ট্যটি রয়েছে, কীভাবে এটি ব্যবহার করবেন সে সম্পর্কে আপনার সংকলকের সাথে পরামর্শ করুন।
নাথান অলিভার

4
@ লন্ডিন, স্বাক্ষরিত পূর্ণসংখ্যার উপস্থাপনের জন্য স্ট্যান্ডার্ডের শব্দগঠনটি পুরোপুরি ভালভাবে পরিচালনা করতে পারে যেখানে শূন্য মানের বিট রয়েছে, অনুমোদিত তিনটি বিকল্পের মধ্যে কমপক্ষে দু'জনের মধ্যে। এটি কাজ করে কারণ এটি অ্যালগোরিদমিক ব্যাখ্যা দেওয়ার পরিবর্তে বিটগুলিকে স্বাক্ষর করার জন্য (নেতিবাচক) স্থানের মান নির্ধারণ করে ।
জন বলিঞ্জার

10

আপনি এটি 2 এর পরিপূরক সিস্টেমে হিসাবে ভাবতে পারেন, বাম দিকের বিটটি হ'ল সাইন বিট। বাম-সর্বাধিক বিট সেট সহ যে কোনও স্বাক্ষরিত পূর্ণসংখ্যার এটি একটি নেতিবাচক মান।

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

1 বিট স্বাক্ষরিত পূর্ণসংখ্যার মানটি হ'ল -2^(n-1)= -2^(1-1)= -2^0= -1এবং2^n-1= 2^1-1=0


8

অনুযায়ী C ++ স্ট্যান্ডার্ডের n4713 , একটি খুব অনুরূপ কোড স্নিপেট প্রদান করা হয়। ব্যবহৃত BOOLধরণটি (কাস্টম), তবে এটি যে কোনও প্রকারে প্রযোজ্য।

12.2.4

4 যদি সত্য বা মিথ্যা মানটিboolকোনও আকারের বিট-ফিল্ডে (এক বিট বিট-ক্ষেত্র সহ)সঞ্চিত থাকেতবে মূলboolমান এবং বিট-ফিল্ডের মান সমান তুলনা করতে হবে। যদি একটি গণকের মান একই গণনা প্রকারের বিট-ফিল্ডে সঞ্চিত থাকে এবং বিট-ফিল্ডে বিটের সংখ্যা যথেষ্ট পরিমাণে থাকে তবে সেই গণনা প্রকারের (10.2) সমস্ত মান ধরে রাখতে পারে, আসল গণকের মান এবং বিট-ফিল্ডের মান সমান তুলনা করবে । [উদাহরণ:

enum BOOL { FALSE=0, TRUE=1 };
struct A {
  BOOL b:1;
};
A a;
void f() {
  a.b = TRUE;
  if (a.b == TRUE)    // yields true
    { /* ... */ }
}

- শেষ উদাহরণ]


প্রথম নজরে, সাহসের অংশটি ব্যাখ্যার জন্য উন্মুক্ত প্রদর্শিত হয়। যাইহোক, সঠিক অভিপ্রায়টি স্পষ্ট হয়ে যায় যখন এর enum BOOLথেকে প্রাপ্ত int

enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
struct mystruct { BOOL enabled:1; };
int main()
{
  struct mystruct s;
  s.enabled = TRUE;
  if(s.enabled == TRUE)
    printf("Is enabled\n"); // --> we think this to be printed
  else
    printf("Is disabled !!\n");
}

উপরের কোড সহ এটি ছাড়াই একটি সতর্কতা দেয় -Wall -pedantic:

সতর্কতা: 'মাইস্ট্রাকট :: :: সক্ষম' এনাম বিওএল-এর সমস্ত মান ধরে রাখতে খুব ছোট struct mystruct { BOOL enabled:1; };

আউটপুটটি হ'ল:

নিষ্ক্রিয় করা !! (ব্যবহার করার সময় enum BOOL : int)

যদি enum BOOL : intসাধারণ করা হয় enum BOOL, তবে উপরের স্ট্যান্ডার্ড প্যাসেজটি নির্দিষ্ট করে যেমন আউটপুট হয়:

সক্ষম করা হয়েছে (ব্যবহার করার সময় enum BOOL)


অতএব, এটি উপসংহারে পৌঁছানো যায়, অন্য কয়েকটি উত্তর যেমন রয়েছে, কেবলমাত্র একক বিট-ফিল্ডে মান "1" সংরক্ষণ করার জন্য এই intধরণের পরিমাণটি বড় নয়।


0

আমি দেখতে পাচ্ছি এমন বিটফিল্ডগুলি বোঝার ক্ষেত্রে কোনও ভুল নেই। আমি যা দেখতে পাচ্ছি তা হল আপনি মাইস্ট্রাক্টকে প্রথমে স্ট্রাক্ট মাইস্ট্রাকট-ইন সক্ষম করে: 1; } এবং তারপর হিসাবে struct হয় mystruct; s । আপনার কোড করা উচিত ছিল:

#include <stdio.h>

struct mystruct { int enabled:1; };
int main()
{
    mystruct s; <-- Get rid of "struct" type declaration
    s.enabled = 1;
    if(s.enabled == 1)
        printf("Is enabled\n"); // --> we think this to be printed
    else
        printf("Is disabled !!\n");
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.