বিভিন্ন সংকলকগুলিতে সি ++ এবং সি এর মধ্যে স্বাক্ষরযুক্ত বিটফিল্ড পূর্ণসংখ্যা এক্সপ্রেশনগুলির অসঙ্গত ছাঁটাই


10

সম্পাদনা 2 :

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

অপরাধী এই অভিব্যক্তি:

ctl.b.p52 << 12;

এখানে, p52টাইপ করা হয় uint64_t; এটি একটি ইউনিয়নেরও একটি অংশ ( control_tনীচে দেখুন)। শিফট অপারেশন কোনও তথ্য হারাবে না কারণ ফলাফলটি এখনও 64 বিটে ফিট করে। তবে, আমি যদি সি সংকলক ব্যবহার করি তবে জিসিসি 52 বিটে ফলাফল কেটে নেওয়ার সিদ্ধান্ত নেয় ! সি ++ সংকলক সহ, ফলাফলের সমস্ত 64 বিট সংরক্ষণ করা হয়।

এটি চিত্রিত করার জন্য, নীচের উদাহরণস্বরূপ প্রোগ্রামটি অভিন্ন সংস্থাগুলির সাথে দুটি ফাংশন সংকলন করে এবং তারপরে তার ফলাফলগুলির সাথে তুলনা করে। c_behavior()একটি সি উত্স ফাইল এবং cpp_behavior()একটি সি ++ ফাইলে রাখা main()হয় এবং তুলনা করে does

উদাহরণ কোড সহ ভান্ডারগুলি: https://github.com/grigory-rechistov/c-cpp-bitfields

শিরোনাম কমন। 64৪-বিট প্রশস্ত বিটফিল্ড এবং পূর্ণসংখ্যার একটি ইউনিয়ন সংজ্ঞায়িত করে এবং দুটি ফাংশন ঘোষণা করে:

#ifndef COMMON_H
#define COMMON_H

#include <stdint.h>

typedef union control {
        uint64_t q;
        struct {
                uint64_t a: 1;
                uint64_t b: 1;
                uint64_t c: 1;
                uint64_t d: 1;
                uint64_t e: 1;
                uint64_t f: 1;
                uint64_t g: 4;
                uint64_t h: 1;
                uint64_t i: 1;
                uint64_t p52: 52;
        } b;
} control_t;

#ifdef __cplusplus
extern "C" {
#endif

uint64_t cpp_behavior(control_t ctl);
uint64_t c_behavior(control_t ctl);

#ifdef __cplusplus
}
#endif

#endif // COMMON_H

ফাংশনগুলির অভিন্ন সংস্থা রয়েছে, সেগুলি ব্যতীত একজনকে সি হিসাবে এবং অন্যটি সি ++ হিসাবে বিবেচনা করা হয়।

সি-part.c:

#include <stdint.h>
#include "common.h"
uint64_t c_behavior(control_t ctl) {
    return ctl.b.p52 << 12;
}

CPP-part.cpp:

#include <stdint.h>
#include "common.h"
uint64_t cpp_behavior(control_t ctl) {
    return ctl.b.p52 << 12;
}

main.c:

#include <stdio.h>
#include "common.h"

int main() {
    control_t ctl;
    ctl.q = 0xfffffffd80236000ull;

    uint64_t c_res = c_behavior(ctl);
    uint64_t cpp_res = cpp_behavior(ctl);
    const char *announce = c_res == cpp_res? "C == C++" : "OMG C != C++";
    printf("%s\n", announce);

    return c_res == cpp_res? 0: 1;
}

জিসিসি তাদের ফলাফলের ফলাফলের মধ্যে পার্থক্য দেখায়:

$ gcc -Wpedantic main.c c-part.c cpp-part.cpp

$ ./a.exe
OMG C != C++

তবে, ঝনঝন সি এবং সি ++ এর সাথে অভিন্ন এবং প্রত্যাশার মতো আচরণ করুন:

$ clang -Wpedantic main.c c-part.c cpp-part.cpp

$ ./a.exe
C == C++

ভিজ্যুয়াল স্টুডিওর সাথে আমি কলংয়ের মতো একই ফলাফল পেয়েছি:

C:\Users\user\Documents>cl main.c c-part.c cpp-part.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24234.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

main.c
c-part.c
Generating Code...
Compiling...
cpp-part.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 14.00.24234.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe
main.obj
c-part.obj
cpp-part.obj

C:\Users\user\Documents>main.exe
C == C++

আমি উইন্ডোজে উদাহরণগুলি চেষ্টা করেছিলাম, যদিও জিসিসির সাথে মূল সমস্যাটি লিনাক্সে আবিষ্কার হয়েছিল।


1
বিট-ফিল্ডগুলি বৃহত্তর প্রস্থের জন্য কুখ্যাত b : আমি এই প্রশ্নে অনুরূপ বিষয় জুড়ে এসেছিল stackoverflow.com/questions/58846584/...
chqrlie

@ chqrlie আমি সি <<অপারেটরটি ছাঁটাইয়ের প্রয়োজনীয়তা হিসাবে পড়েছি ।
অ্যান্ড্রু হেনেল

দয়া করে একটি স্ট্যাকওভারফ্লো . com/help/minimal-reproducible- উদাহরণ পোস্ট করুন । বর্তমান main.cকোডটির কোনও নেই এবং সম্ভবত বিভিন্ন উপায়ে অপরিজ্ঞাত আচরণের কারণ রয়েছে। আইএমও এটি একটি একক-ফাইল এমআরই পোস্ট করা আরও স্পষ্ট হবে যা প্রতিটি সংকলক দিয়ে সংকলন করার সময় বিভিন্ন আউটপুট উত্পাদন করে। কারণ সি-সি ++ ইন্টারপ মানক দ্বারা ভালভাবে নির্দিষ্ট করা যায় না। এছাড়াও নোট করুন যে ইউনিয়ন আলিয়াসিংয়ের ফলে C ++ তে ইউবি হয়।
এমএম

@ এমএম ডান, আমি প্রশ্ন পোস্ট করার সময় এটি পিছলে গেছে। আমি এখন এটি যুক্ত করেছি এবং আমিও মনে করি এটির সাথে একটি ছোট ভাণ্ডার থাকাও একটি ধারণা হতে পারে
গ্রিগরি রেকিস্টভ

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

উত্তর:


6

সি এবং সি ++ বিট-ফিল্ড সদস্যদের প্রকারের সাথে আলাদাভাবে আচরণ করে।

সি 2018 6.7.2.1 10 বলেছেন:

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

এটি প্রকারের বিষয়ে নির্দিষ্ট নয় serve এটি কিছু পূর্ণসংখ্যার প্রকার about এবং এটি যে প্রকারে বিট-ফিল্ড ঘোষণার জন্য ব্যবহৃত হয়েছিল তা নয় বলে জানায় uint64_t a : 1; এবং প্রশ্নের মধ্যে দেখানো । এটি স্পষ্টতই প্রকারটি চয়ন করার জন্য এটি প্রয়োগের জন্য উন্মুক্ত করে দেয়।

সি ++ 2017 খসড়া n4659 12.2.4 [শ্রেণী.বিট] 1 বিট-ফিল্ড ঘোষণার বিষয়ে বলেছেন:

… বিট-ফিল্ড বৈশিষ্ট্যটি শ্রেণীর সদস্যের ধরণের অংশ নয় ...

এই থেকেই বোঝা যায়, একটি ঘোষণায় যেমন uint64_t a : 1;, : 1না বর্গ সদস্য ধরণ অংশ a, তাই টাইপ হিসাবে যদি এটি ছিল uint64_t a;ধরণ, এবং এইভাবে aহয়uint64_t

সুতরাং দেখা যাচ্ছে যে জিসিসি সি-তে কিছুটা বিট-ফিল্ডকে কিছু সংখ্যক টাইপ 32-বিট বা সংকীর্ণ হিসাবে মানায় এবং সি ++ তে বিট-ফিল্ডকে তার ঘোষিত প্রকার হিসাবে বিবেচনা করে এবং এটি মানদণ্ড লঙ্ঘন করে বলে মনে হয় না।


আমি প্রতি in.৫. 4 4 প্রতি বাধ্যতামূলক হিসাবে সি তে ছাঁটাই পড়েছি (সি 18 শব্দটি একই রকম): "E1 << E2 এর ফলাফল E1 বাম-স্থানান্তরিত E2 বিট পজিশন; খালি বিটগুলি শূন্যে ভরা হয়। যদি E1 এর স্বাক্ষরবিহীন প্রকার থাকে , ফলাফলের মান হ'ল E1 x 2E2, ফলাফলের ধরণটিতে উপস্থাপনযোগ্য সর্বোচ্চ মানের তুলনায় মডুলোকে আরও একটি হ্রাস করা হয়েছে। " E1এই ক্ষেত্রে একটি 52-বিট বিট-ফিল্ড।
অ্যান্ড্রু হেনেল

@ অ্যান্ড্রুহেনেল: আপনি যা বলছেন তা আমি দেখতে পাচ্ছি। একটি এন- বিট বিট-ফিল্ডের ধরণ হ'ল " এন- বিট পূর্ণসংখ্যা" (আপাতত স্বাক্ষরকে অবহেলা করা)। আমি এটিকে এন- বিট বিট-ফিল্ডের ধরণ হিসাবে সংখ্যার পূর্ণসংখ্যার টাইপ হিসাবে ব্যাখ্যা করছি , যা বাস্তবায়ন বেছে নেয়। কেবলমাত্র 6.7.2.1 10 এ শব্দের উপর ভিত্তি করে, আমি আপনার ব্যাখ্যার পক্ষে। কিন্তু যে একটি সমস্যা যে একটি দেওয়া হয় uint64_t a : 33একটি কাঠামো 2 ^ 33-1 সেট sহলে, 32 বিট সঙ্গে একটি সি বাস্তবায়নের int, s.a+s.a2 ^ 33-2 মোড়ানো কারণে উত্পাদ উচিত, কিন্তু ঝনঝন 2 ^ 34- উত্পাদন করে 2; এটি দৃশ্যত এটি হিসাবে হিসাবে আচরণ করে uint64_t
এরিক পোস্টপিসিল

@ অ্যান্ড্রুহেনেল: (যুক্তির আরও কারণ: s.a+s.aসাধারণত গাণিতিক রূপান্তরগুলি ধরণের পরিবর্তিত হবে না s.a, যেহেতু এটির চেয়ে বেশি বিস্তৃত unsigned int, তাই পাটিগণিতটি 33-বিট প্রকারে সম্পন্ন হবে।)
এরিক পোস্টপিসিল

তবে কলং 2 ^ 34-22 উত্পাদন করে; এটি দৃশ্যত এটি হিসাবে হিসাবে আচরণ করে uint64_t যদি এটি একটি -৪-বিট সংকলন হয় তবে মনে হয় যে জঙ্গি কীভাবে ছাঁটাই না করে 64৪-বিট সংকলনগুলি চিকিত্সা করছে তার সাথে ঝাঁকুনি সামঞ্জস্য করে। কলং কি 32- এবং 64-বিট সংকলনগুলি আলাদাভাবে আচরণ করে? (এবং মনে হচ্ছে আমি বিট ফিল্ডগুলি এড়ানোর জন্য আরও একটি কারণ শিখেছি ...)
অ্যান্ড্রু হেনেল

@ অ্যান্ড্রুহেনেল: আচ্ছা, পুরানো অ্যাপল ক্ল্যাং 1.7 2 ^ 32−2 (2 ^ 33-22 নয়; এটি কিছুটা হারাতে পেরেছে!) উভয়ই দিয়েছিল -m32এবং -m64এই ধরণের একটি জিসিসি এক্সটেনশন বলে একটি সতর্কতা সহ with অ্যাপল ক্ল্যাং ১১.০ সহ, আমার কাছে 32-বিট কোড চালানোর জন্য লাইব্রেরি নেই, তবে উত্পন্ন সমাবেশটি প্রদর্শন করা pushl $3এবং pushl $-2কল করার আগে printf, তাই আমি মনে করি এটি 2 ^ 34-22। সুতরাং অ্যাপল ক্ল্যাং 32-বিট এবং 64-বিট লক্ষ্যগুলির মধ্যে পার্থক্য করছে না তবে সময়ের সাথে সাথে এটি পরিবর্তিত হয়েছে।
এরিক পোস্টপিসিল

4

অ্যান্ড্রু হেনেল সি স্ট্যান্ডার্ডের একটি কঠোর ব্যাখ্যার পরামর্শ দিয়েছিলেন: বিট-ফিল্ডের ধরণটি হ'ল নির্দিষ্ট প্রস্থের সাথে স্বাক্ষরযুক্ত বা স্বাক্ষরবিহীন পূর্ণসংখ্যার প্রকার।

এখানে একটি পরীক্ষা যা এই ব্যাখ্যাকে সমর্থন করে: C1x _Generic()নির্মাণ ব্যবহার করে , আমি বিভিন্ন প্রস্থের বিট-ফিল্ডগুলির ধরণ নির্ধারণ করার চেষ্টা করছি। long long intঝনঝনির সাথে সংকলন করার সময় সতর্কতা এড়াতে আমাকে তাদের টাইপ দিয়ে সংজ্ঞায়িত করতে হয়েছিল ।

উত্সটি এখানে:

#include <stdint.h>
#include <stdio.h>

#define typeof(X)  _Generic((X),                         \
                       long double: "long double",       \
                       double: "double",                 \
                       float: "float",                   \
                       unsigned long long int: "unsigned long long int",  \
                       long long int: "long long int",   \
                       unsigned long int: "unsigned long int",  \
                       long int: "long int",             \
                       unsigned int: "unsigned int",     \
                       int: "int",                       \
                       unsigned short: "unsigned short", \
                       short: "short",                   \
                       unsigned char: "unsigned char",   \
                       signed char: "signed char",       \
                       char: "char",                     \
                       _Bool: "_Bool",                   \
                       __int128_t: "__int128_t",         \
                       __uint128_t: "__uint128_t",       \
                       default: "other")

#define stype long long int
#define utype unsigned long long int

struct s {
    stype s1 : 1;
    stype s2 : 2;
    stype s3 : 3;
    stype s4 : 4;
    stype s5 : 5;
    stype s6 : 6;
    stype s7 : 7;
    stype s8 : 8;
    stype s9 : 9;
    stype s10 : 10;
    stype s11 : 11;
    stype s12 : 12;
    stype s13 : 13;
    stype s14 : 14;
    stype s15 : 15;
    stype s16 : 16;
    stype s17 : 17;
    stype s18 : 18;
    stype s19 : 19;
    stype s20 : 20;
    stype s21 : 21;
    stype s22 : 22;
    stype s23 : 23;
    stype s24 : 24;
    stype s25 : 25;
    stype s26 : 26;
    stype s27 : 27;
    stype s28 : 28;
    stype s29 : 29;
    stype s30 : 30;
    stype s31 : 31;
    stype s32 : 32;
    stype s33 : 33;
    stype s34 : 34;
    stype s35 : 35;
    stype s36 : 36;
    stype s37 : 37;
    stype s38 : 38;
    stype s39 : 39;
    stype s40 : 40;
    stype s41 : 41;
    stype s42 : 42;
    stype s43 : 43;
    stype s44 : 44;
    stype s45 : 45;
    stype s46 : 46;
    stype s47 : 47;
    stype s48 : 48;
    stype s49 : 49;
    stype s50 : 50;
    stype s51 : 51;
    stype s52 : 52;
    stype s53 : 53;
    stype s54 : 54;
    stype s55 : 55;
    stype s56 : 56;
    stype s57 : 57;
    stype s58 : 58;
    stype s59 : 59;
    stype s60 : 60;
    stype s61 : 61;
    stype s62 : 62;
    stype s63 : 63;
    stype s64 : 64;

    utype u1 : 1;
    utype u2 : 2;
    utype u3 : 3;
    utype u4 : 4;
    utype u5 : 5;
    utype u6 : 6;
    utype u7 : 7;
    utype u8 : 8;
    utype u9 : 9;
    utype u10 : 10;
    utype u11 : 11;
    utype u12 : 12;
    utype u13 : 13;
    utype u14 : 14;
    utype u15 : 15;
    utype u16 : 16;
    utype u17 : 17;
    utype u18 : 18;
    utype u19 : 19;
    utype u20 : 20;
    utype u21 : 21;
    utype u22 : 22;
    utype u23 : 23;
    utype u24 : 24;
    utype u25 : 25;
    utype u26 : 26;
    utype u27 : 27;
    utype u28 : 28;
    utype u29 : 29;
    utype u30 : 30;
    utype u31 : 31;
    utype u32 : 32;
    utype u33 : 33;
    utype u34 : 34;
    utype u35 : 35;
    utype u36 : 36;
    utype u37 : 37;
    utype u38 : 38;
    utype u39 : 39;
    utype u40 : 40;
    utype u41 : 41;
    utype u42 : 42;
    utype u43 : 43;
    utype u44 : 44;
    utype u45 : 45;
    utype u46 : 46;
    utype u47 : 47;
    utype u48 : 48;
    utype u49 : 49;
    utype u50 : 50;
    utype u51 : 51;
    utype u52 : 52;
    utype u53 : 53;
    utype u54 : 54;
    utype u55 : 55;
    utype u56 : 56;
    utype u57 : 57;
    utype u58 : 58;
    utype u59 : 59;
    utype u60 : 60;
    utype u61 : 61;
    utype u62 : 62;
    utype u63 : 63;
    utype u64 : 64;
} x;

int main(void) {
#define X(v)  printf("typeof(" #v "): %s\n", typeof(v))
    X(x.s1);
    X(x.s2);
    X(x.s3);
    X(x.s4);
    X(x.s5);
    X(x.s6);
    X(x.s7);
    X(x.s8);
    X(x.s9);
    X(x.s10);
    X(x.s11);
    X(x.s12);
    X(x.s13);
    X(x.s14);
    X(x.s15);
    X(x.s16);
    X(x.s17);
    X(x.s18);
    X(x.s19);
    X(x.s20);
    X(x.s21);
    X(x.s22);
    X(x.s23);
    X(x.s24);
    X(x.s25);
    X(x.s26);
    X(x.s27);
    X(x.s28);
    X(x.s29);
    X(x.s30);
    X(x.s31);
    X(x.s32);
    X(x.s33);
    X(x.s34);
    X(x.s35);
    X(x.s36);
    X(x.s37);
    X(x.s38);
    X(x.s39);
    X(x.s40);
    X(x.s41);
    X(x.s42);
    X(x.s43);
    X(x.s44);
    X(x.s45);
    X(x.s46);
    X(x.s47);
    X(x.s48);
    X(x.s49);
    X(x.s50);
    X(x.s51);
    X(x.s52);
    X(x.s53);
    X(x.s54);
    X(x.s55);
    X(x.s56);
    X(x.s57);
    X(x.s58);
    X(x.s59);
    X(x.s60);
    X(x.s61);
    X(x.s62);
    X(x.s63);
    X(x.s64);

    X(x.u1);
    X(x.u2);
    X(x.u3);
    X(x.u4);
    X(x.u5);
    X(x.u6);
    X(x.u7);
    X(x.u8);
    X(x.u9);
    X(x.u10);
    X(x.u11);
    X(x.u12);
    X(x.u13);
    X(x.u14);
    X(x.u15);
    X(x.u16);
    X(x.u17);
    X(x.u18);
    X(x.u19);
    X(x.u20);
    X(x.u21);
    X(x.u22);
    X(x.u23);
    X(x.u24);
    X(x.u25);
    X(x.u26);
    X(x.u27);
    X(x.u28);
    X(x.u29);
    X(x.u30);
    X(x.u31);
    X(x.u32);
    X(x.u33);
    X(x.u34);
    X(x.u35);
    X(x.u36);
    X(x.u37);
    X(x.u38);
    X(x.u39);
    X(x.u40);
    X(x.u41);
    X(x.u42);
    X(x.u43);
    X(x.u44);
    X(x.u45);
    X(x.u46);
    X(x.u47);
    X(x.u48);
    X(x.u49);
    X(x.u50);
    X(x.u51);
    X(x.u52);
    X(x.u53);
    X(x.u54);
    X(x.u55);
    X(x.u56);
    X(x.u57);
    X(x.u58);
    X(x.u59);
    X(x.u60);
    X(x.u61);
    X(x.u62);
    X(x.u63);
    X(x.u64);

    return 0;
}

এখানে প্রোগ্রামটির আউটপুটটি 64-বিট বিড়ম্বনার সাথে সংকলিত রয়েছে:

typeof(x.s1): long long int
typeof(x.s2): long long int
typeof(x.s3): long long int
typeof(x.s4): long long int
typeof(x.s5): long long int
typeof(x.s6): long long int
typeof(x.s7): long long int
typeof(x.s8): long long int
typeof(x.s9): long long int
typeof(x.s10): long long int
typeof(x.s11): long long int
typeof(x.s12): long long int
typeof(x.s13): long long int
typeof(x.s14): long long int
typeof(x.s15): long long int
typeof(x.s16): long long int
typeof(x.s17): long long int
typeof(x.s18): long long int
typeof(x.s19): long long int
typeof(x.s20): long long int
typeof(x.s21): long long int
typeof(x.s22): long long int
typeof(x.s23): long long int
typeof(x.s24): long long int
typeof(x.s25): long long int
typeof(x.s26): long long int
typeof(x.s27): long long int
typeof(x.s28): long long int
typeof(x.s29): long long int
typeof(x.s30): long long int
typeof(x.s31): long long int
typeof(x.s32): long long int
typeof(x.s33): long long int
typeof(x.s34): long long int
typeof(x.s35): long long int
typeof(x.s36): long long int
typeof(x.s37): long long int
typeof(x.s38): long long int
typeof(x.s39): long long int
typeof(x.s40): long long int
typeof(x.s41): long long int
typeof(x.s42): long long int
typeof(x.s43): long long int
typeof(x.s44): long long int
typeof(x.s45): long long int
typeof(x.s46): long long int
typeof(x.s47): long long int
typeof(x.s48): long long int
typeof(x.s49): long long int
typeof(x.s50): long long int
typeof(x.s51): long long int
typeof(x.s52): long long int
typeof(x.s53): long long int
typeof(x.s54): long long int
typeof(x.s55): long long int
typeof(x.s56): long long int
typeof(x.s57): long long int
typeof(x.s58): long long int
typeof(x.s59): long long int
typeof(x.s60): long long int
typeof(x.s61): long long int
typeof(x.s62): long long int
typeof(x.s63): long long int
typeof(x.s64): long long int
typeof(x.u1): unsigned long long int
typeof(x.u2): unsigned long long int
typeof(x.u3): unsigned long long int
typeof(x.u4): unsigned long long int
typeof(x.u5): unsigned long long int
typeof(x.u6): unsigned long long int
typeof(x.u7): unsigned long long int
typeof(x.u8): unsigned long long int
typeof(x.u9): unsigned long long int
typeof(x.u10): unsigned long long int
typeof(x.u11): unsigned long long int
typeof(x.u12): unsigned long long int
typeof(x.u13): unsigned long long int
typeof(x.u14): unsigned long long int
typeof(x.u15): unsigned long long int
typeof(x.u16): unsigned long long int
typeof(x.u17): unsigned long long int
typeof(x.u18): unsigned long long int
typeof(x.u19): unsigned long long int
typeof(x.u20): unsigned long long int
typeof(x.u21): unsigned long long int
typeof(x.u22): unsigned long long int
typeof(x.u23): unsigned long long int
typeof(x.u24): unsigned long long int
typeof(x.u25): unsigned long long int
typeof(x.u26): unsigned long long int
typeof(x.u27): unsigned long long int
typeof(x.u28): unsigned long long int
typeof(x.u29): unsigned long long int
typeof(x.u30): unsigned long long int
typeof(x.u31): unsigned long long int
typeof(x.u32): unsigned long long int
typeof(x.u33): unsigned long long int
typeof(x.u34): unsigned long long int
typeof(x.u35): unsigned long long int
typeof(x.u36): unsigned long long int
typeof(x.u37): unsigned long long int
typeof(x.u38): unsigned long long int
typeof(x.u39): unsigned long long int
typeof(x.u40): unsigned long long int
typeof(x.u41): unsigned long long int
typeof(x.u42): unsigned long long int
typeof(x.u43): unsigned long long int
typeof(x.u44): unsigned long long int
typeof(x.u45): unsigned long long int
typeof(x.u45): unsigned long long int
typeof(x.u46): unsigned long long int
typeof(x.u47): unsigned long long int
typeof(x.u48): unsigned long long int
typeof(x.u49): unsigned long long int
typeof(x.u50): unsigned long long int
typeof(x.u51): unsigned long long int
typeof(x.u52): unsigned long long int
typeof(x.u53): unsigned long long int
typeof(x.u54): unsigned long long int
typeof(x.u55): unsigned long long int
typeof(x.u56): unsigned long long int
typeof(x.u57): unsigned long long int
typeof(x.u58): unsigned long long int
typeof(x.u59): unsigned long long int
typeof(x.u60): unsigned long long int
typeof(x.u61): unsigned long long int
typeof(x.u62): unsigned long long int
typeof(x.u63): unsigned long long int
typeof(x.u64): unsigned long long int

সমস্ত বিট-ফিল্ডের সংজ্ঞায়িত প্রস্থের জন্য নির্দিষ্ট প্রকারের পরিবর্তে সংজ্ঞায়িত প্রকারের মনে হয়।

এখানে প্রোগ্রামটির আউটপুটটি 64-বিট জিসিসি দিয়ে সংকলিত হয়েছে:

typestr(x.s1): other
typestr(x.s2): other
typestr(x.s3): other
typestr(x.s4): other
typestr(x.s5): other
typestr(x.s6): other
typestr(x.s7): other
typestr(x.s8): signed char
typestr(x.s9): other
typestr(x.s10): other
typestr(x.s11): other
typestr(x.s12): other
typestr(x.s13): other
typestr(x.s14): other
typestr(x.s15): other
typestr(x.s16): short
typestr(x.s17): other
typestr(x.s18): other
typestr(x.s19): other
typestr(x.s20): other
typestr(x.s21): other
typestr(x.s22): other
typestr(x.s23): other
typestr(x.s24): other
typestr(x.s25): other
typestr(x.s26): other
typestr(x.s27): other
typestr(x.s28): other
typestr(x.s29): other
typestr(x.s30): other
typestr(x.s31): other
typestr(x.s32): int
typestr(x.s33): other
typestr(x.s34): other
typestr(x.s35): other
typestr(x.s36): other
typestr(x.s37): other
typestr(x.s38): other
typestr(x.s39): other
typestr(x.s40): other
typestr(x.s41): other
typestr(x.s42): other
typestr(x.s43): other
typestr(x.s44): other
typestr(x.s45): other
typestr(x.s46): other
typestr(x.s47): other
typestr(x.s48): other
typestr(x.s49): other
typestr(x.s50): other
typestr(x.s51): other
typestr(x.s52): other
typestr(x.s53): other
typestr(x.s54): other
typestr(x.s55): other
typestr(x.s56): other
typestr(x.s57): other
typestr(x.s58): other
typestr(x.s59): other
typestr(x.s60): other
typestr(x.s61): other
typestr(x.s62): other
typestr(x.s63): other
typestr(x.s64): long long int
typestr(x.u1): other
typestr(x.u2): other
typestr(x.u3): other
typestr(x.u4): other
typestr(x.u5): other
typestr(x.u6): other
typestr(x.u7): other
typestr(x.u8): unsigned char
typestr(x.u9): other
typestr(x.u10): other
typestr(x.u11): other
typestr(x.u12): other
typestr(x.u13): other
typestr(x.u14): other
typestr(x.u15): other
typestr(x.u16): unsigned short
typestr(x.u17): other
typestr(x.u18): other
typestr(x.u19): other
typestr(x.u20): other
typestr(x.u21): other
typestr(x.u22): other
typestr(x.u23): other
typestr(x.u24): other
typestr(x.u25): other
typestr(x.u26): other
typestr(x.u27): other
typestr(x.u28): other
typestr(x.u29): other
typestr(x.u30): other
typestr(x.u31): other
typestr(x.u32): unsigned int
typestr(x.u33): other
typestr(x.u34): other
typestr(x.u35): other
typestr(x.u36): other
typestr(x.u37): other
typestr(x.u38): other
typestr(x.u39): other
typestr(x.u40): other
typestr(x.u41): other
typestr(x.u42): other
typestr(x.u43): other
typestr(x.u44): other
typestr(x.u45): other
typestr(x.u46): other
typestr(x.u47): other
typestr(x.u48): other
typestr(x.u49): other
typestr(x.u50): other
typestr(x.u51): other
typestr(x.u52): other
typestr(x.u53): other
typestr(x.u54): other
typestr(x.u55): other
typestr(x.u56): other
typestr(x.u57): other
typestr(x.u58): other
typestr(x.u59): other
typestr(x.u60): other
typestr(x.u61): other
typestr(x.u62): other
typestr(x.u63): other
typestr(x.u64): unsigned long long int

যা প্রতিটি প্রস্থের সাথে আলাদা আলাদা ধরণের থাকে consistent

অভিব্যক্তি E1 << E2বাম পদোন্নতি প্রতীক, তাই কোনো প্রস্থ কম টাইপ হয়েছে INT_WIDTHউন্নীত করা হয় intমাধ্যমে পূর্ণসংখ্যা প্রচার এবং ছাড়া প্রস্থ বৃহত্তর INT_WIDTHএকা ছেড়ে দেওয়া হয়। এই প্রস্থটি এর চেয়ে বেশি হলে অভিব্যক্তির ফলাফলটি বিট-ফিল্ডের প্রস্থে কাটা উচিতINT_WIDTH । আরও স্পষ্টভাবে, এটি একটি স্বাক্ষরবিহীন প্রকারের জন্য কেটে ফেলা উচিত এবং এটি স্বাক্ষরিত ধরণের জন্য সংজ্ঞায়িত বাস্তবায়ন হতে পারে।

এর চেয়ে বড় প্রস্থের বিট-ফিল্ডগুলি E1 + E2থাকলে E1বা অন্যান্য পাটিগণিত অপারেটরগুলির E2ক্ষেত্রে একই হবে int। আরও ছোট প্রস্থের অপারেন্ডটি বৃহত্তর প্রস্থের সাথে টাইপে রূপান্তরিত হয় এবং ফলাফলটিও টাইপ টাইপ করে। এই বিপরীতমুখী স্বজ্ঞাত আচরণটি অনেক অপ্রত্যাশিত ফলাফলের সৃষ্টি করে, বিট-ফিল্ডগুলি বোগাস এবং এড়ানো উচিত এই বিস্তৃত বিশ্বাসের কারণ হতে পারে।

অনেক সংকলক সি স্ট্যান্ডার্ডের এই ব্যাখ্যাকে অনুসরণ করে বলে মনে হয় না, এবং বর্তমান ব্যাখ্যাটি থেকে এই ব্যাখ্যাটি স্পষ্ট নয়। সি স্ট্যান্ডার্ডের ভবিষ্যতের সংস্করণে বিট-ফিল্ড অপারেশনগুলিকে জড়িত পাটিগণিতের ক্রিয়াকলাপগুলির শব্দার্থবিজ্ঞানগুলি স্পষ্ট করা কার্যকর হবে।


1
আমি মনে করি মূল শব্দটি হ'ল পূর্ণসংখ্যা '। পূর্ণসংখ্যা প্রচারের সাথে বিট-ফিল্ডগুলির আলোচনা (C11 §6.3.1.1 - যদি কোনও intমূল ধরণের সমস্ত মানকে উপস্থাপন করতে পারে (বিট-ফিল্ডের জন্য প্রস্থ দ্বারা সীমাবদ্ধ হিসাবে), মানটি intunsigned intএকটিতে রূপান্তরিত হয় , অন্যথায়, এটি এটিকে রূপান্তর করা হয় These এগুলিকে পূর্ণসংখ্যা প্রচার বলা হয় - - .36.3.1.8 , §6.7.2.1 ), যেখানে বিট-ফিল্ডের প্রস্থের চেয়ে প্রস্থ প্রশস্ত হয় তার প্রচ্ছদটি কাভার করবেন না int
জোনাথন লেফলার

1
এটা সাহায্য না যে মান পাতার undefined করে (শ্রেষ্ঠ সময়ে বাস্তবায়ন-সংজ্ঞায়িত) কি ধরনের ছাড়া অন্য বিট-ক্ষেত্রের জন্য অনুমতি দেওয়া হয় int, unsigned intএবং _Bool
জোনাথন লেফলার

1
"32 এর চেয়ে কম প্রস্থ", "32 এর চেয়ে বেশি প্রস্থ" এবং "যদি এই প্রস্থ 32 এর চেয়ে বেশি হয়" এর সম্ভবত সম্ভবত বিট সংখ্যাটি প্রতিবিম্বিত করা উচিত intএবং এটি একটি স্থির 32 নয়।
বেন ভোইগট

1
আমি সম্মত হই যে সি স্ট্যান্ডার্ডে কোনও সমস্যা (তদারকি)। তর্ক করার অবকাশ থাকতে পারে যেহেতু স্ট্যান্ডার্ডটি uint64_tবিট-ফিল্ডগুলি ব্যবহারের অনুমতি দেয় না, তাই মানকগুলি তাদের সম্পর্কে কিছু বলতে পারে না - এটি বাস্তবায়নের সংজ্ঞায়িত অংশগুলির বাস্তবায়নের ডকুমেন্টেশন দ্বারা আবৃত হওয়া উচিত বিট ফিল্ডস বিশেষত, কেবলমাত্র বিট-ফিল্ডের 52-বিট কোনও (32-বিট) int-র সাথে খাপ খায় না এর অর্থ এটি হওয়া উচিত নয় যে তারা 32-বিটের মধ্যে স্ক্র্যাচ করে চলেছে unsigned int, তবে এটি 6.3 এর আক্ষরিক পাঠ্য। 1.1 বলেছেন।
জোনাথন লেফলার

1
এছাড়াও, যদি সি ++ 'বিট বিট-ফিল্ড' সমস্যাগুলি স্পষ্টভাবে সমাধান করেছে, তবে সি যে নেতৃত্বটি যথাসম্ভব ঘনিষ্ঠভাবে অনুসরণ করা উচিত - যদি না সেই রেজোলিউশন (যা সম্ভবত না) সম্পর্কে সি ++ এর অন্তর্নিহিত নির্দিষ্ট কিছু না থাকে।
জোনাথন লেফলার

2

সমস্যাটি সিসি মোডে জিসিসির 32-বিট কোড জেনারেটরের সাথে নির্দিষ্ট বলে মনে হচ্ছে:

আপনি গডবোল্টের সংকলক এক্সপ্লোরার ব্যবহার করে সমাবেশ কোডটি তুলনা করতে পারেন

এই পরীক্ষার উত্স কোডটি এখানে:

#include <stdint.h>

typedef union control {
    uint64_t q;
    struct {
        uint64_t a: 1;
        uint64_t b: 1;
        uint64_t c: 1;
        uint64_t d: 1;
        uint64_t e: 1;
        uint64_t f: 1;
        uint64_t g: 4;
        uint64_t h: 1;
        uint64_t i: 1;
        uint64_t p52: 52;
    } b;
} control_t;

uint64_t test(control_t ctl) {
    return ctl.b.p52 << 12;
}

সি মোডে আউটপুট (পতাকা -xc -O2 -m32)

test:
        push    esi
        push    ebx
        mov     ebx, DWORD PTR [esp+16]
        mov     ecx, DWORD PTR [esp+12]
        mov     esi, ebx
        shr     ebx, 12
        shr     ecx, 12
        sal     esi, 20
        mov     edx, ebx
        pop     ebx
        or      esi, ecx
        mov     eax, esi
        shld    edx, esi, 12
        pop     esi
        sal     eax, 12
        and     edx, 1048575
        ret

সমস্যাটি হ'ল শেষ নির্দেশ and edx, 1048575যা 12 সবচেয়ে গুরুত্বপূর্ণ বিটকে ক্লিপ করে।

সি ++ মোডের আউটপুটটি সর্বশেষ নির্দেশ ব্যতীত অভিন্ন:

test(control):
        push    esi
        push    ebx
        mov     ebx, DWORD PTR [esp+16]
        mov     ecx, DWORD PTR [esp+12]
        mov     esi, ebx
        shr     ebx, 12
        shr     ecx, 12
        sal     esi, 20
        mov     edx, ebx
        pop     ebx
        or      esi, ecx
        mov     eax, esi
        shld    edx, esi, 12
        pop     esi
        sal     eax, 12
        ret

-৪-বিট মোডে আউটপুটটি অনেক সহজ এবং সঠিক, সি এবং সি ++ সংকলকগুলির জন্য পৃথক:

#C code:
test:
        movabs  rax, 4503599627366400
        and     rax, rdi
        ret

# C++ code:
test(control):
        mov     rax, rdi
        and     rax, -4096
        ret

জিসিসি বাগ ট্র্যাকারে আপনার একটি বাগ রিপোর্ট ফাইল করা উচিত।


আমার পরীক্ষাগুলি কেবলমাত্র -৪-বিট লক্ষ্যমাত্রার জন্য ছিল তবে আপনার ৩২-বিট কেসটি আরও বিসারের। আমি অনুমান করি যে একটি বাগ রিপোর্ট আসবে due প্রথমত, আমার কাছে এটি উপলব্ধ একটি সর্বশেষ জিসিসি সংস্করণে পুনরায় পরীক্ষা করা দরকার।
গ্রিগরি রিচিস্তভ

1
@ গ্রেগরিরিচিস্টভ সি স্ট্যান্ডার্ডে শব্দটি দেওয়া , বাগটি খুব ভালভাবে well৪- বিটের লক্ষ্য হতে পারে ফলাফলটি 52 বিটের নিচে কাটাতে ব্যর্থ হতে পারে। আমি ব্যক্তিগতভাবে এটি দেখতে হবে।
অ্যান্ড্রু হেনেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.