আমি কীভাবে একটি সি ++ শ্রেণীর মেমরি স্ট্রাকচারে একটি "স্পেসার" তৈরি করব?


94

সমস্যাটি

একটি নিম্ন স্তরের বেয়ার মেটাল এমবেডেড প্রসঙ্গ, আমি একটি সি ++ কাঠামোর মধ্যে এবং কোন নাম ছাড়া মেমরির মধ্যে একটি ফাঁকা স্থান তৈরি করতে, অ্যাক্সেস মেমরি অবস্থানকে ব্যবহারকারী নিষেধ করতে চাই।

এই মুহুর্তে, আমি এটি একটি uint32_t :96;কুরুচিপূর্ণ বিটফিল্ড স্থাপন করে অর্জন করেছি যা সহজেই তিনটি শব্দের স্থান গ্রহণ করবে, তবে এটি জিসিসির কাছ থেকে একটি সতর্কতা উত্থাপন করবে (বিটফিল্ড uint32_t ফিট করতে খুব বড় হবে না) এটি বেশ বৈধ is

এটি কার্যকরভাবে কাজ করার সময়, আপনি যখন কয়েকশ সতর্কতা দিয়ে একটি লাইব্রেরি বিতরণ করতে চান তখন খুব পরিষ্কার হয় না ...

আমি কীভাবে এটি সঠিকভাবে করব?

প্রথমদিকে কেন একটি সমস্যা আছে?

আমি যে প্রকল্পে কাজ করছি তাতে সম্পূর্ণ মাইক্রোকন্ট্রোলার লাইনের (এসটিএমক্রোইলেকট্রনিক্স এসটিএম 32) বিভিন্ন পেরিফেরিয়ালগুলির মেমরি কাঠামো সংজ্ঞায়িত করে। এটি করার জন্য, ফলাফলটি এমন একটি শ্রেণী যা লক্ষ্যযুক্ত মাইক্রোকন্ট্রোলারের উপর নির্ভর করে সমস্ত রেজিস্ট্রার সংজ্ঞায়িত করে এমন বেশ কয়েকটি কাঠামোর একটি ইউনিয়ন ধারণ করে।

বেশ সহজ পেরিফেরিয়ালগুলির জন্য একটি সাধারণ উদাহরণ নিম্নরূপ: একটি সাধারণ উদ্দেশ্য ইনপুট / আউটপুট (জিপিআইও)

union
{

    struct
    {
        GPIO_MAP0_MODER;
        GPIO_MAP0_OTYPER;
        GPIO_MAP0_OSPEEDR;
        GPIO_MAP0_PUPDR;
        GPIO_MAP0_IDR;
        GPIO_MAP0_ODR;
        GPIO_MAP0_BSRR;
        GPIO_MAP0_LCKR;
        GPIO_MAP0_AFR;
        GPIO_MAP0_BRR;
        GPIO_MAP0_ASCR;
    };
    struct
    {
        GPIO_MAP1_CRL;
        GPIO_MAP1_CRH;
        GPIO_MAP1_IDR;
        GPIO_MAP1_ODR;
        GPIO_MAP1_BSRR;
        GPIO_MAP1_BRR;
        GPIO_MAP1_LCKR;
        uint32_t :32;
        GPIO_MAP1_AFRL;
        GPIO_MAP1_AFRH;
        uint32_t :64;
    };
    struct
    {
        uint32_t :192;
        GPIO_MAP2_BSRRL;
        GPIO_MAP2_BSRRH;
        uint32_t :160;
    };
};

যেখানে সমস্তই GPIO_MAPx_YYYম্যাক্রো, হিসাবে নির্ধারিত হয় uint32_t :32বা নিবন্ধের ধরণ (উত্সর্গীকৃত কাঠামো)।

এখানে আপনি uint32_t :192;যা ভালভাবে কাজ করে তা দেখতে পান তবে এটি একটি সতর্কবার্তা ট্রিগার করে।

আমি এখন পর্যন্ত যা বিবেচনা করেছি:

আমি এটি বেশ কয়েকটি uint32_t :32;(এখানে 6) দ্বারা প্রতিস্থাপন করতে পারি, তবে আমার কিছু চরম ঘটনা রয়েছে যেখানে আমার uint32_t :1344;(42) (অন্যদের মধ্যে) রয়েছে। সুতরাং আমি 8k অন্যদের উপরে প্রায় একশ লাইন যুক্ত করব না, যদিও কাঠামো প্রজন্মের স্ক্রিপ্ট করা আছে।

যথাযথ সতর্কতা বার্তাটি হ'ল: width of 'sool::ll::GPIO::<anonymous union>::<anonymous struct>::<anonymous>' exceeds its type(আমি কেবল এটি কতটা ছায়াময় তা পছন্দ করি)।

আমি বরং এটি কেবল সতর্কতা অপসারণ করেই সমাধান করব না , তবে ব্যবহার করব

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-WTheRightFlag"
/* My code */
#pragma GCC diagnostic pop

সমাধান হতে পারে ... যদি আমি পাই TheRightFlag। যাইহোক, এই থ্রেডে উল্লেখ করা হিসাবে , gcc/cp/class.cএই দু: খিত কোড অংশ সহ:

warning_at (DECL_SOURCE_LOCATION (field), 0,
        "width of %qD exceeds its type", field);

যা আমাদের জানিয়েছে যে -Wxxxএই সতর্কতাটি সরাতে কোনও পতাকা নেই ...


26
আপনি কি বিবেচনা করেছেন char unused[12];ইত্যাদি?
এমএম

4
আমি কেবল সতর্কতা দমন করব। [শ্রেণী.বিট] / 1 এর আচরণের গ্যারান্টি দেয় uint32_t :192;
নাথানঅলিভার

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

4
BTW আপনি লিখতে পারেন :42*32পরিবর্তে:1344
এম এম

4
সতর্কতা দমন করার জন্য এটি চেষ্টা করবেন? gcc.gnu.org/onlinesocs/gcc/…
হিটোব্যাট

উত্তর:


36

একাধিক সংলগ্ন বেনামে বিটফিল্ড ব্যবহার করুন। এর পরিবর্তে:

    uint32_t :160;

উদাহরণস্বরূপ, আপনি চাইবেন:

    uint32_t :32;
    uint32_t :32;
    uint32_t :32;
    uint32_t :32;
    uint32_t :32;

প্রতিটি নিবন্ধের জন্য একটি করে আপনি বেনামে থাকতে চান।

আপনার যদি পূরণ করার জন্য বৃহত্তর স্থান থাকে তবে এটি একক 32 বিট জায়গার পুনরাবৃত্তি করতে ম্যাক্রোগুলি ব্যবহার করতে আরও পরিষ্কার এবং কম ত্রুটিযুক্ত হতে পারে। উদাহরণস্বরূপ, প্রদত্ত:

#define REPEAT_2(a) a a
#define REPEAT_4(a) REPEAT_2(a) REPEAT_2(a)
#define REPEAT_8(a) REPEAT_4(a) REPEAT_4(a)
#define REPEAT_16(a) REPEAT_8(a) REPEAT_8(a)
#define REPEAT_32(a) REPEAT_16(a) REPEAT_16(a)

তারপরে একটি 1344 (42 * 32 বিট) স্থান এভাবে যুক্ত করা যেতে পারে:

struct
{
    ...
    REPEAT_32(uint32_t :32;) 
    REPEAT_8(uint32_t :32;) 
    REPEAT_2(uint32_t :32;)
    ...
};

উত্তর করার জন্য ধন্যবাদ. আমি ইতিমধ্যে বিবেচনা করেছি, তবে এটি আমার কয়েকটি ফাইলে 200 টিরও বেশি লাইন যুক্ত করবে ( uint32_t :1344;জায়গাটিতে রয়েছে) সুতরাং আমাকে বরং এই পথে যেতে হবে না ...
জে ফাচার

4
@ জেফাউচার আপনার লাইন গণনা প্রয়োজনীয়তার একটি সম্ভাব্য সমাধান যুক্ত করেছেন। আপনার যদি এ জাতীয় প্রয়োজনীয়তা থাকে তবে আপনি যে উত্তরগুলি পূরণ করেন না সেগুলি পেতে এড়াতে আপনি তাদের প্রশ্নের মধ্যে উল্লেখ করতে পারেন।
ক্লিফোর্ড

সম্পাদনার জন্য ধন্যবাদ এবং লাইন গণনা জিনিসটি উল্লেখ না করার জন্য দুঃখিত। আমার বক্তব্যটি হ'ল আমার কোডটি ডুব দেওয়ার জন্য ইতিমধ্যে বেদনাদায়ক কারণ এখানে প্রচুর লাইন রয়েছে এবং আমি আরও বেশি যুক্ত করা এড়াতে চাই। অতএব, আমি জিজ্ঞাসা করছিলাম যে কেউ সংলগ্ন বেনামে বিটফিল্ড ব্যবহার করা এড়াতে কোনও "ক্লিন" বা "অফিসিয়াল" উপায় জানেন কিনা (এমনকি এটি কার্যকর থাকলেও)। যদিও ম্যাক্রো অ্যাপ্রোচ আমার কাছে ভাল লাগছে। উপায় দ্বারা, আপনার উদাহরণস্বরূপ, আপনি কি 36 * 32 বিট স্থান পেয়েছেন?
জে ফাচার

@ জেফৌচার - সংশোধন করা হয়েছে। I / O রেজিস্টার ম্যাপিং ফাইলগুলি প্রচুর সংখ্যক নিবন্ধকের কারণে অগত্যা বড় - সাধারণত আপনি একবার লেখেন, এবং রক্ষণাবেক্ষণ কোনও সমস্যা নয় কারণ হার্ডওয়্যারটি একটি ধ্রুবক। "আড়াল" রেজিস্টারগুলি বাদে আপনি যদি পরে তাদের অ্যাক্সেসের প্রয়োজন হয় তবে আপনি নিজের জন্য রক্ষণাবেক্ষণের কাজ করছেন। আপনি অবশ্যই অবগত আছেন যে সমস্ত এসটিএম 32 ডিভাইসে ইতিমধ্যে বিক্রেতার দ্বারা সরবরাহকৃত একটি রেজিস্টার মানচিত্রের শিরোনাম রয়েছে? এটি ব্যবহার করা ত্রুটি-প্রবণতা থেকে অনেক কম হবে।
ক্লিফোর্ড

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

45

কীভাবে সি ++ - ইশ ওয়ে?

namespace GPIO {

static volatile uint32_t &MAP0_MODER = *reinterpret_cast<uint32_t*>(0x4000);
static volatile uint32_t &MAP0_OTYPER = *reinterpret_cast<uint32_t*>(0x4004);

}

int main() {
    GPIO::MAP0_MODER = 42;
}

GPIOনেমস্পেসের কারণে আপনি অটোকম্প্লেশন পান এবং ডামি প্যাডিংয়ের দরকার নেই। এমনকি, এটি কী চলছে তা আরও স্পষ্ট, যেমন আপনি প্রতিটি নিবন্ধকের ঠিকানা দেখতে পাচ্ছেন, আপনাকে সংকলকের প্যাডিং আচরণের উপর মোটেই নির্ভর করতে হবে না।


4
এটি একই ফাংশন থেকে একাধিক এমএমআইও রেজিস্টারগুলিতে অ্যাক্সেসের জন্য কাঠামোর চেয়ে কম ভাল অপ্টিমাইজ করতে পারে। একটি রেজিস্টারে বেস ঠিকানার পয়েন্টার সহ, সংকলক তাত্ক্ষণিক স্থানচ্যুতি সহ লোড / স্টোর নির্দেশাবলী ব্যবহার করতে পারে ldr r0, [r4, #16], যখন সংকলক পৃথকভাবে ঘোষণা করা প্রতিটি ঠিকানার সাথে সেই অপটিমাইজেশন মিস করতে পারে। জিসিসি সম্ভবত প্রতিটি জিপিআইও ঠিকানা আলাদা রেজিষ্টারে লোড করবে। (একটি আক্ষরিক পুল থেকে, যদিও তাদের কিছু থাম্ব এনকোডিংয়ে ঘোরানো ইমিডিয়েট হিসাবে প্রতিনিধিত্ব করা যেতে পারে))
পিটার কর্ডেস

4
আমার উদ্বেগ ভিত্তিহীন ছিল; এআরএম জিসিসিও এইভাবে অনুকূলিত করে। Godbolt.org/z/ztB7hi । তবে নোট করুন যে আপনি চান static volatile uint32_t &MAP0_MODER, না inline। একটি inlineভেরিয়েবল সংকলন করে না। ( staticপয়েন্টারের জন্য কোনও স্ট্যাটিক স্টোরেজ থাকা এড়িয়ে যাওয়া এবং volatileএমএমআইওর কাছে ডেড-স্টোর নির্মূলকরণ বা লেখার / পড়ার পিছনের অনুকূলকরণ এড়াতে আপনি ঠিক এটি চান))
পিটার কর্ডেস

4
@ পিটারকর্ডস: ইনলাইন ভেরিয়েবলগুলি একটি নতুন সি ++ 17 বৈশিষ্ট্য। তবে আপনি ঠিক বলেছেন, staticএই ক্ষেত্রে সমানভাবে ভাল কাজ করে। উল্লেখ করার জন্য ধন্যবাদ volatile, আমি এটিকে আমার উত্তরে যুক্ত করব (এবং স্থিতিতে ইনলাইন পরিবর্তন করব, সুতরাং এটি প্রাক সি ++ 17 এর জন্য কাজ করে)।
গেজা

4
এটি কঠোরভাবে সংজ্ঞায়িত আচরণ নয় যে এই টুইটার থ্রেডটি দেখুন এবং সম্ভবত এটি কার্যকর হয়
শফিক ইয়াঘমোর

4
@ জেফাউচার: আপনার যত স্ট্রাক্ট রয়েছে তত বেশি নেমস্পেস তৈরি করুন এবং সেই নামস্থানে স্ট্যান্ডেলোন ফাংশন ব্যবহার করুন। সুতরাং, আপনার হবে GPIOA::togglePin()
geza

20

এম্বেড থাকা সিস্টেমের ক্ষেত্রে, আপনি কাঠামো ব্যবহার করে বা রেজিস্টার ঠিকানাগুলিতে পয়েন্টার নির্ধারণ করে হার্ডওয়্যারকে মডেল করতে পারেন।

কাঠামো অনুসারে মডেলিংয়ের প্রস্তাব দেওয়া হয় না কারণ সংযোজক উদ্দেশ্যে প্রান্তিককরণের জন্য সদস্যদের মধ্যে প্যাডিং যুক্ত করার অনুমতি দেওয়া হয়েছে (যদিও এমবেডেড সিস্টেমগুলির জন্য অনেক সংকলক কাঠামোর প্যাকিংয়ের জন্য প্রগমা রয়েছে)।

উদাহরণ:

uint16_t * const UART1 = (uint16_t *)(0x40000);
const unsigned int UART_STATUS_OFFSET = 1U;
const unsigned int UART_TRANSMIT_REGISTER = 2U;
uint16_t * const UART1_STATUS_REGISTER = (UART1 + UART_STATUS_OFFSET);
uint16_t * const UART1_TRANSMIT_REGISTER = (UART1 + UART_TRANSMIT_REGISTER);

আপনি অ্যারে স্বরলিপি ব্যবহার করতে পারেন:

uint16_t status = UART1[UART_STATUS_OFFSET];  

আপনার যদি অবশ্যই কাঠামো, আইএমএইচও ব্যবহার করতে হবে তবে ঠিকানাগুলি এড়িয়ে যাওয়ার সর্বোত্তম পদ্ধতিটি হ'ল কোনও সদস্যকে সংজ্ঞায়িত করা এবং এটি অ্যাক্সেস না করা:

struct UART1
{
  uint16_t status;
  uint16_t reserved1; // Transmit register
  uint16_t receive_register;
};

আমাদের প্রকল্পগুলির একটিতে আমাদের কাছে বিভিন্ন বিক্রেতাদের কাছ থেকে ধ্রুবক এবং স্ট্রাক উভয়ই রয়েছে (বিক্রেতারা 1 কনস্ট্যান্ট ব্যবহার করেন এবং বিক্রেতারা স্ট্রাকচার ব্যবহার করেন 2)।


আপনার উত্তরের জন্য ধন্যবাদ. যাইহোক, আমি যখন কোনও স্বয়ং-সম্পূর্ণ বৈশিষ্ট্য পেলাম (আপনার কেবলমাত্র সঠিক বৈশিষ্ট্য প্রদর্শিত হবে) এবং ব্যবহারকারীকে সংরক্ষিত স্লটগুলি "প্রদর্শন" করতে আমি চাই না তবে ব্যবহারকারীর কাজ সহজ করার জন্য আমি একটি কাঠামো পদ্ধতির ব্যবহার বেছে নিই and আমার প্রথম পোস্টের একটি মন্তব্যে নির্দেশিত।
জে ফাউচার 23

আপনি এখনও থাকতে পারেন যে উপরের ঠিকানাটির staticকাঠামোর সদস্য তৈরি করে স্বতঃসম্পূর্ণ স্থিতিশীল সদস্যদের দেখাতে সক্ষম um যদি তা না হয় তবে এটি ইনলাইন সদস্যের কাজগুলিও হতে পারে।
ফিল 1970

@ জেফাউচার আমি এম্বেড থাকা সিস্টেমের ব্যক্তি নই এবং এটি পরীক্ষাও করেছি না, তবে কি সংরক্ষিত সদস্যকে ব্যক্তিগত ঘোষণা করে স্বয়ংক্রিয়রূপটি সমাধান করা হবে না? (আপনি একটি কাঠামোতে ব্যক্তিগত সদস্যদের ঘোষণা করতে পারেন, এবং ক্ষেত্রগুলির সঠিক ক্রম পেতে আপনি public:এবং private:যতবার আপনি চান ততবার ব্যবহার করতে পারেন ))
নাথানিয়েল

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

4
volatileবিটিডব্লিউ, মেমরি-ম্যাপযুক্ত আই / ও রেজিস্ট্রারগুলির জন্য বিটিডব্লিউ, এই ঘোষণাগুলি ভুলে যাবেন না ।
পিটার কর্ডেস

13

geza এর অধিকার যে আপনি সত্যিই এই জন্য ক্লাস ব্যবহার করা চাই না।

তবে, যদি আপনি জোর দিয়ে থাকেন তবে এন বাইটের প্রস্থের অব্যক্ত সদস্যকে যুক্ত করার সর্বোত্তম উপায়টি কেবল এটি করা:

char unused[n];

আপনি যদি শ্রেণীর সদস্যদের মধ্যে স্বেচ্ছাসেবক প্যাডিং যোগ করা রোধ করতে একটি প্রয়োগ-নির্দিষ্ট প্রগমা যোগ করেন তবে এটি কাজ করতে পারে।


জিএনইউ সি / সি ++ (জিসিসি, ঝনঝন, এবং অন্যান্য যারা একই এক্সটেনশনগুলি সমর্থন করে) এর জন্য, বৈশিষ্ট্যটি রাখার জন্য বৈধ স্থানগুলির মধ্যে একটি হ'ল:

#include <stddef.h>
#include <stdint.h>
#include <assert.h>  // for C11 static_assert, so this is valid C as well as C++

struct __attribute__((packed)) GPIO {
    volatile uint32_t a;
    char unused[3];
    volatile uint32_t b;
};

static_assert(offsetof(struct GPIO, b) == 7, "wrong GPIO struct layout");

(উদাহরণস্বরূপ গডবোল্ট সংকলক এক্সপ্লোরারoffsetof(GPIO, b) = 7 বাইট দেখায় )


9

@ ক্লিফোর্ড এবং @ অ্যাডাম কোটওয়াসিনস্কির উত্তরগুলিতে প্রসারিত করতে:

#define REP10(a)        a a a a a a a a a a
#define REP1034(a)      REP10(REP10(REP10(a))) REP10(a a a) a a a a

struct foo {
        int before;
        REP1034(unsigned int :32;)
        int after;
};
int main(void){
        struct foo bar;
        return 0;
}

আমি আমার মন্তব্যে আপনার পরামর্শের বৈকল্পিকটি একটি মন্তব্যে আরও প্রয়োজনীয়তা অনুসরণ করে অন্তর্ভুক্ত করেছি । যেখানে দেনা আছে সেখানে দেনা পরিশোধ করুন।
ক্লিফোর্ড

7

ক্লিফোর্ডের উত্তরে প্রসারিত করতে আপনি বরাবর বেনামে বিটফিল্ডগুলি ম্যাক্রো করতে পারেন।

পরিবর্তে তাই

uint32_t :160;

ব্যবহার

#define EMPTY_32_1 \
 uint32_t :32
#define EMPTY_32_2 \
 uint32_t :32;     \ // I guess this also can be replaced with uint64_t :64
 uint32_t :32
#define EMPTY_32_3 \
 uint32_t :32;     \
 uint32_t :32;     \
 uint32_t :32
#define EMPTY_UINT32(N) EMPTY_32_ ## N

এবং তারপরে এটি ব্যবহার করুন

struct A {
  EMPTY_UINT32(3);
  /* which resolves to EMPTY_32_3, which then resolves to real declarations */
}

দুর্ভাগ্যক্রমে, আপনার EMPTY_32_Xযতগুলি বাইট রয়েছে তার জন্য আপনার যতগুলি বৈকল্পিক প্রয়োজন :( তবুও, এটি আপনাকে আপনার স্ট্রাক্টে একক ঘোষণার অনুমতি দেয়।


5
বুস্ট সিপিপি ম্যাক্রো ব্যবহার করে, আমি মনে করি আপনি প্রয়োজনীয় সমস্ত ম্যাক্রোগুলি হাতে না এড়াতে পুনরাবৃত্তিটি ব্যবহার করতে পারেন।
পিটার কর্ডেস

4
আপনি এগুলি ক্যাসকেড করতে পারেন (প্রিপ্রোসেসর পুনরাবৃত্তি সীমা পর্যন্ত, তবে এটি সাধারণত পর্যাপ্ত)। তাই #define EMPTY_32_2 EMPTY_32_1; EMPTY_32_1এবং #define EMPTY_32_3 EMPTY_32_2; EMPTY_32_1ইত্যাদি
মিরাল

@ পিটারকর্ডস সম্ভবত, তবে ট্যাগগুলি ইঙ্গিত দেয় যে সম্ভবত বুথ সি এবং সি ++ সামঞ্জস্যতা প্রয়োজন।
ক্লিফোর্ড 12

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

1

একটি বড় স্পেসারকে 32 বিটের গ্রুপ হিসাবে সংজ্ঞায়িত করতে।

#define M_32(x)   M_2(M_16(x))
#define M_16(x)   M_2(M_8(x))
#define M_8(x)    M_2(M_4(x))
#define M_4(x)    M_2(M_2(x))
#define M_2(x)    x x

#define SPACER int : 32;

struct {
    M_32(SPACER) M_8(SPACER) M_4(SPACER)
};

1

আমি মনে করি এটি আরও কিছু কাঠামো প্রবর্তন করা উপকারী হবে; যা পরিবর্তে স্পেসারদের সমস্যা সমাধান করতে পারে।

রূপগুলির নাম দিন

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

প্রথম পদক্ষেপ হিসাবে, আমি তাই ভাঙ্গারstruct বিবেচনা করব :

// GpioMap0.h
#pragma once

// #includes

namespace Gpio {
struct Map0 {
    GPIO_MAP0_MODER;
    GPIO_MAP0_OTYPER;
    GPIO_MAP0_OSPEEDR;
    GPIO_MAP0_PUPDR;
    GPIO_MAP0_IDR;
    GPIO_MAP0_ODR;
    GPIO_MAP0_BSRR;
    GPIO_MAP0_LCKR;
    GPIO_MAP0_AFR;
    GPIO_MAP0_BRR;
    GPIO_MAP0_ASCR;
};
} // namespace Gpio

// GpioMap1.h
#pragma once

// #includes

namespace Gpio {
struct Map1 {
    // fields
};
} // namespace Gpio

// ... others headers ...

এবং অবশেষে, গ্লোবাল শিরোনাম:

// Gpio.h
#pragma once

#include "GpioMap0.h"
#include "GpioMap1.h"
// ... other headers ...

namespace Gpio {
union Gpio {
    Map0 map0;
    Map1 map1;
    // ... others ...
};
} // namespace Gpio

এখন, আমি একটি লিখতে পারি void special_map0(Gpio:: Map0 volatile& map);, পাশাপাশি এক নজরে সমস্ত উপলব্ধ আর্কিটেকচারের একটি দ্রুত ওভারভিউ পেতে পারি।

সাধারণ স্পেসার্স

সংজ্ঞাটি একাধিক শিরোনামে বিভক্ত হয়ে গেলে শিরোনামগুলি স্বতন্ত্রভাবে অনেক বেশি পরিচালিত হয়।

অতএব, আপনার প্রয়োজনীয়তা ঠিক পূরণের জন্য আমার প্রাথমিক পদ্ধতিটি পুনরাবৃত্তি সহকারে স্থির থাকবে std::uint32_t:32;। হ্যাঁ, এটি বিদ্যমান 8 কে লাইনে কয়েকটি 100s লাইন যুক্ত করে, তবে প্রতিটি শিরোনাম স্বতন্ত্রভাবে ছোট হওয়ায় এটি ততটা খারাপ নাও হতে পারে।

আপনি আরও বহিরাগত সমাধান বিবেচনা করতে ইচ্ছুক থাকলেও, ...

পরিচয় করানো $।

এটি একটি সামান্য-পরিচিত সত্য যা $সি ++ শনাক্তকারীদের জন্য একটি কার্যকর চরিত্র; এটি এমনকি একটি ব্যবহার্য শুরুর অক্ষর (অঙ্কগুলির বিপরীতে)।

একটি $সোর্স কোড প্রদর্শনে সম্ভবত ভ্রু বাড়াতে হবে, এবং $$$$স্পষ্টভাবে কোড রিভিউ সময় মনোযোগ আকর্ষণ করতে যাচ্ছে। এটি এমন কিছু যা আপনি সহজেই নিতে পারেন:

#define GPIO_RESERVED(Index_, N_) std::uint32_t $$$$##Index_[N_];

struct Map3 {
    GPIO_RESERVED(0, 6);
    GPIO_MAP2_BSRRL;
    GPIO_MAP2_BSRRH;
    GPIO_RESERVED(1, 5);
};

এমনকি আপনি প্রাক-কমিট হুক হিসাবে বা আপনার সিআইতে একটি সাধারণ "লিন্ট" একসাথে রাখতে পারেন যা $$$$প্রতিশ্রুতিবদ্ধ সি ++ কোড সন্ধান করে এবং এই জাতীয় কমিটি প্রত্যাখ্যান করে।


4
মনে রাখবেন যে ওপি-র নির্দিষ্ট ব্যবহারের কেসটি সংকলকটিতে মেমরি-ম্যাপযুক্ত I / O নিবন্ধগুলির বর্ণনা দেওয়ার জন্য। এটা তোলে কখনো মান পুরো struct হয় কপি করতে জ্ঞান করে তোলে। (এবং প্রতিটি সদস্যের GPIO_MAP0_MODERমতামত volatileসম্ভবত:) পূর্ববর্তী-বেনাম সদস্যদের সম্ভবত রেফারেন্স বা টেম্পলেট-প্যারামিটার ব্যবহার দরকারী হতে পারে। এবং প্যাডিং স্ট্রোকগুলির সাধারণ ক্ষেত্রে, নিশ্চিত। তবে ইউপ-কেস ব্যাখ্যা করে যে ওপি কেন তাদের বেনামে রেখেছিল।
পিটার কর্ডেস 21

আপনি যদি $$$padding##Index_[N_];ক্ষেত্রের নামটি স্ব-পরিপূরণে বা ডিবাগিংয়ের ক্ষেত্রে কখনও সামনে আসে সে ক্ষেত্রে ক্ষেত্রের নামটি আরও স্ব-ব্যাখ্যামূলক হিসাবে ব্যবহার করতে পারেন। (বা নাম অনুসারে zz$$$paddingবাছাই করার জন্য GPIO..., কারণ ওপি অনুসারে এই অনুশীলনের পুরো পয়েন্টটি মেমরি-ম্যাপযুক্ত I / O অবস্থানের নামগুলির জন্য সুন্দর স্বতঃপূরণ))
পিটার কর্ডেস

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

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

4
@ পিটারকর্ডস: আমি রেফারেন্স দিয়ে যাবার কথা ভাবছিলাম, যা পরে নিচে চিত্রিত হয়েছে। আমি এটিকে উদ্ভট বলে মনে করি যে ওপির কাঠামো তাদের "মডিউল" তৈরি করা থেকে বিরত রাখে যা কেবলমাত্র একটি নির্দিষ্ট আর্কিটেকচার অ্যাক্সেসের জন্য স্থিরভাবে প্রমাণিত হতে পারে (নির্দিষ্ট কোনও রেফারেন্স গ্রহণ করে struct) এবং unionশেষটি এমনকি আর্কিটেকচার-নির্দিষ্ট বিটগুলিতে সর্বত্র প্রচার করা হয় যা অন্যদের সম্পর্কে কম যত্ন করতে পারে।
ম্যাথিউ এম।

0

যদিও আমি সম্মত হয়েছি যে স্ট্রাইকগুলি এমসিইউ আই / ও পোর্ট অ্যাক্সেসের জন্য ব্যবহার করা উচিত নয়, মূল প্রশ্নের উত্তর এভাবে দেওয়া যেতে পারে:

struct __attribute__((packed)) test {
       char member1;
       char member2;
       volatile struct __attribute__((packed))
       {
       private:
              volatile char spacer_bytes[7];
       }  spacer;
       char member3;
       char member4;
};

আপনার সংকলক সিনট্যাক্সের উপর নির্ভর করে আপনার __attribute__((packed))সাথে প্রতিস্থাপনের প্রয়োজন হতে পারে #pragma pack

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

কোনও কারণে জিসিসি একটি সতর্কতা তৈরি করে যদি কোনও বেনামি কাঠামোর সদস্য ব্যক্তিগত হয় তাই আমাকে এটির নাম দিতে হয়েছিল। বিকল্পভাবে, এটি অন্য একটি বেনামে কাঠামোতে মোড়ানো সতর্কতা থেকে মুক্তি পেয়েছে (এটি কোনও ত্রুটি হতে পারে)।

নোট করুন যে spacerসদস্যটি নিজেই ব্যক্তিগত নয়, সুতরাং এখনও এই উপায়ে অ্যাক্সেস করা যায়:

(char*)(void*)&testobj.spacer;

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


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

ধন্যবাদ, এটি স্থির করুন।
জ্যাক হোয়াইট

-1

বিরোধী সমাধান।

এটি করবেন না: ব্যক্তিগত এবং সরকারী ক্ষেত্রগুলি মেশান।

সম্ভবত ইউনিট ভেরিয়েবলের নাম তৈরি করতে কাউন্টার সহ একটি ম্যাক্রো কার্যকর হবে?

#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define RESERVED MACRO_CONCAT(Reserved_var, __COUNTER__) 


struct {
    GPIO_MAP1_CRL;
    GPIO_MAP1_CRH;
    GPIO_MAP1_IDR;
    GPIO_MAP1_ODR;
    GPIO_MAP1_BSRR;
    GPIO_MAP1_BRR;
    GPIO_MAP1_LCKR;
private:
    char RESERVED[4];
public:
    GPIO_MAP1_AFRL;
    GPIO_MAP1_AFRH;
private:
    char RESERVED[8];
};


4
ঠিক আছে. যদি কেউ কিছু মনে না করে তবে আমি উত্তরটি কী করব না তা হিসাবে ছেড়ে দেব।
রবার্ট অ্যান্ড্রেজুক 11

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

4
@ অলিভ এবং আমি -1 করলাম কারণ ওপি-তে কিছু প্রয়োজন ছিল, এই উত্তরটি প্রয়োজনীয়তা লঙ্ঘন করেছে, এবং তাই এটি একটি খারাপ উত্তর। আমি স্পষ্টভাবে কোনও মূল্য মন্তব্য, ব্যক্তির পক্ষে, ইতিবাচক বা নেতিবাচক, কোনও মন্তব্যেই করিনি - কেবলমাত্র উত্তরের উপর। আমি মনে করি আমরা দুজনেই একমত হতে পারি এটি খারাপ। ব্যক্তি সম্পর্কে যা যা বলে তা এই সাইটের জন্য অফ-টপিক। (যদিও আইএমও কেউ কিছু সময় একটি ধারণা অবদান নিতে ইচ্ছুক করছে কিছু ঠিক আছে, এমনকি যদি ধারণা প্যান না)
ফান্ড মনিকা এর মামলা

4
হ্যাঁ এটি ভুল উত্তর। তবে আমি আশঙ্কা করছি কিছু লোক একই ধারণাতে আসতে পারে। মন্তব্য এবং লিঙ্কের কারণে আমি সবেমাত্র কিছু শিখেছি, এটি আমার পক্ষে নেতিবাচক বিষয় নয়।
রবার্ট আন্দ্রেজুক 19
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.