سؤال

أحاول تنفيذ فكرة ضغط البيانات التي خطرت ببالي، وبما أنني أتخيل تشغيلها مقابل مجموعة كبيرة من بيانات الاختبار، فقد فكرت في ترميزها بلغة C (لدي خبرة في الغالب في لغات البرمجة النصية مثل Ruby و تي سي ال.)

من خلال النظر في كتب O'Reilly "cow" على لغة C، أدركت أنه لا يمكنني ببساطة فهرسة أجزاء متغير بسيط من النوع "char" أو "int" كما أرغب في إجراء مقارنات ومعاملات ثنائية.

هل أنا على حق في هذا التصور؟هل من المعقول بالنسبة لي أن أستخدم نوعًا معدودًا لتمثيل البت (وإنشاء مصفوفة منها، ووظائف الكتابة للتحويل من وإلى char)؟إذا كان الأمر كذلك، فهل تم تعريف هذا النوع والوظائف في مكتبة قياسية في مكان ما بالفعل؟هل هناك طرق أخرى (أفضل؟)؟هل هناك بعض الأمثلة على التعليمات البرمجية في مكان ما يمكن أن يوجهني إليها شخص ما؟

شكرًا -

هل كانت مفيدة؟

المحلول

متابعةً لما قاله كايل، يمكنك استخدام الماكرو للقيام بالعمل الشاق نيابةً عنك.

إنه ممكن.

لتعيين البت n، استخدم OR:

س |= (1 << 5);// يضبط اليمين السادس

لمسح بعض الشيء، استخدم AND:

x &= ~(1 << 5);// يمسح 6 من اليمين

للقلب قليلاً، استخدم XOR:

س ^= (1 << 5);// يقلب المركز السادس من اليمين

أو...

#define GetBit(var, bit) ((var & (1 << bit)) != 0) // Returns true / false if bit is set
#define SetBit(var, bit) (var |= (1 << bit))
#define FlipBit(var, bit) (var ^= (1 << bit))

ثم يمكنك استخدامه في التعليمات البرمجية مثل:

int myVar = 0;
SetBit(myVar, 5);
if (GetBit(myVar, 5))
{
  // Do something
}

نصائح أخرى

إنه ممكن.

لتعيين البت n، استخدم OR:

x |= (1 << 5); // sets the 5th-from right

لمسح بعض الشيء، استخدم AND:

x &= ~(1 << 5); // clears 5th-from-right

للقلب قليلاً، استخدم XOR:

x ^= (1 << 5); // flips 5th-from-right

للحصول على قيمة البت استخدم Shift و AND:

(x & (1 << 5)) >> 5 // gets the value (0 or 1) of the 5th-from-right

ملحوظة:التحول إلى اليمين 5 هو التأكد من أن القيمة إما 0 أو 1.إذا كنت مهتمًا فقط بـ 0/not 0، فيمكنك القيام بذلك دون التحول.

ألق نظرة على الإجابات على هذا السؤال.

نظرية

لا يوجد بناء جملة C للوصول إلى البتة n من نوع البيانات المضمن أو تعيينها (على سبيل المثال."شار").ومع ذلك، يمكنك الوصول إلى البتات باستخدام عملية AND المنطقية، وتعيين البتات باستخدام عملية OR المنطقية.

على سبيل المثال، لنفترض أن لديك متغيرًا يحمل الرقم 1101 وتريد التحقق من البت الثاني من اليسار.ما عليك سوى إجراء AND منطقيًا باستخدام 0100:

1101
0100
---- AND
0100

إذا كانت النتيجة غير صفرية، فيجب تعيين البت الثاني؛وإلا لم يتم تعيين.

إذا كنت تريد تعيين البتة الثالثة من اليسار، فقم بإجراء عملية OR منطقية باستخدام 0010:

1101
0010
---- OR
1111

يمكنك استخدام مشغلات C && (من أجل و) و || (لـ OR) لأداء هذه المهام.ستحتاج إلى إنشاء أنماط الوصول إلى البتات (0100 و0010 في الأمثلة المذكورة أعلاه) بنفسك.الحيلة هي أن تتذكر أن البتة الأقل أهمية (LSB) تحتسب 1s، والبتة الأقل أهمية التالية تحتسب 2s، ثم 4s، وما إلى ذلك.لذلك، فإن نمط الوصول إلى البتات لـ LSB n-th (يبدأ من 0) هو ببساطة قيمة 2^n.أسهل طريقة لحساب ذلك في لغة C هي تحويل القيمة الثنائية 0001 (في هذا المثال المكون من أربعة بتات) إلى اليسار بالعدد المطلوب من الأماكن.نظرًا لأن هذه القيمة تساوي دائمًا 1 بكميات تشبه الأعداد الصحيحة غير الموقعة، فهذا مجرد '1 << n'

مثال

unsigned char myVal = 0x65; /* in hex; this is 01100101 in binary. */

/* Q: is the 3-rd least significant bit set (again, the LSB is the 0th bit)? */
unsigned char pattern = 1;
pattern <<= 3; /* Shift pattern left by three places.*/

if(myVal && (char)(1<<3)) {printf("Yes!\n");} /* Perform the test. */

/* Set the most significant bit. */
myVal |= (char)(1<<7);

لم يتم اختبار هذا المثال، ولكن يجب أن يعمل على توضيح الفكرة العامة.

للاستعلام عن حالة البت باستخدام فهرس محدد:

int index_state = variable & ( 1 << bit_index );

لتعيين البت:

varabile |= 1 << bit_index;

لإعادة تشغيل البت:

variable &= ~( 1 << bit_index );

يمكن فهرسة البتات الفردية على النحو التالي.

تحديد هيكل مثل هذا:

struct
{
  unsigned bit0     : 1;
  unsigned bit1     : 1;
  unsigned bit2     : 1;
  unsigned bit3     : 1;
  unsigned reserved : 28;
} bitPattern;   

الآن، إذا أردت معرفة قيم البت الفردية للمتغير المسمى "value"، فقم بما يلي:

CopyMemory( &input, &value, sizeof(value) );

لمعرفة ما إذا كان البت 2 مرتفعًا أم منخفضًا:

int state = bitPattern.bit2;

أتمنى أن يساعدك هذا.

حاول استخدام حقول البت.كن حذرًا، فقد يختلف التنفيذ حسب المترجم.

http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html

إذا كنت تريد الفهرسة قليلاً، فيمكنك:

bit = (char & 0xF0) >> 7;

يحصل على msb من شار.يمكنك حتى ترك التحول الصحيح وإجراء اختبار على 0.

bit = char & 0xF0;

إذا تم ضبط البت فإن النتيجة ستكون > 0؛

من الواضح أنك تحتاج إلى تغيير القناع للحصول على وحدات بت مختلفة (ملاحظة:0xF هو قناع البت إذا كان غير واضح).من الممكن تحديد العديد من الأقنعة على سبيل المثال.

#define BIT_0 0x1 // or 1 << 0
#define BIT_1 0x2 // or 1 << 1
#define BIT_2 0x4 // or 1 << 2
#define BIT_3 0x8 // or 1 << 3

إلخ...

هذا يمنحك:

bit = char & BIT_1;

يمكنك استخدام هذه التعريفات في الكود أعلاه لفهرسة جزء ما بنجاح داخل ماكرو أو دالة.

لتعيين قليلا:

char |= BIT_2;

لتوضيح قليلا:

char &= ~BIT_3

للتبديل قليلا

char ^= BIT_4

هذه المساعدة؟

توجد حاوية مكتبة قياسية للبتات:الأمراض المنقولة جنسيا::ناقل.وهي متخصصة في المكتبة لتكون فعالة من حيث المساحة.هناك أيضًا فئة Dynamic_bitset معززة.

سيتيح لك ذلك إجراء عمليات على مجموعة من القيم المنطقية، باستخدام بت واحد لكل قيمة للتخزين الأساسي.

تعزيز وثائق مجموعة البت الديناميكية

للحصول على وثائق STL، راجع وثائق المترجم الخاص بك.

بالطبع، يمكنك أيضًا معالجة البتات الفردية في الأنواع المتكاملة الأخرى يدويًا.إذا قمت بذلك، فيجب عليك استخدام الأنواع غير الموقعة حتى لا تحصل على سلوك غير محدد إذا قررت إجراء إزاحة صحيحة على قيمة ذات مجموعة بت عالية.ومع ذلك، يبدو أنك تريد الحاويات.

إلى المعلق الذي ادعى أن هذا يأخذ مساحة أكبر بمقدار 32 مرة من اللازم:إن Boost::dynamic_bitset و Vector مخصصان لاستخدام بت واحد لكل إدخال، وبالتالي لا توجد عقوبة مسافة، على افتراض أنك تريد بالفعل أكثر من عدد البتات في النوع البدائي.تسمح لك هذه الفئات بمعالجة البتات الفردية في حاوية كبيرة ذات مساحة تخزين أساسية فعالة.إذا كنت تريد فقط (على سبيل المثال) 32 بت، فاستخدم int.إذا كنت تريد عددًا كبيرًا من البتات، فيمكنك استخدام حاوية المكتبة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top