मैं C ++ क्लास मेमोरी संरचना में "स्पेसर" कैसे बनाऊं?


94

समस्या

एक में निम्न स्तर नंगे धातु एम्बेडेड संदर्भ, मैं एक सी ++ ढांचे के भीतर है और किसी भी नाम के बिना स्मृति में एक रिक्त स्थान बनाने के लिए, का उपयोग इस तरह के स्मृति स्थान के लिए उपयोगकर्ता मना करना चाहते हैं।

अभी, मैंने इसे एक बदसूरत uint32_t :96;बिटफ़ील्ड डालकर हासिल किया है जो आसानी से तीन शब्दों की जगह ले लेगा, लेकिन यह जीसीसी (बिटफील्ड बहुत बड़ी है जो uint32_t में फिट होने के लिए एक चेतावनी देगा), जो कि बहुत वैध है।

जब यह ठीक काम करता है, तो यह बहुत साफ नहीं होता है जब आप उन सैकड़ों चेतावनियों के साथ एक पुस्तकालय वितरित करना चाहते हैं ...

मैं ठीक से कैसे करूँ?

पहली बार में मुद्दा क्यों है?

जिस प्रोजेक्ट पर मैं काम कर रहा हूं, उसमें पूरे माइक्रोकंट्रोलर लाइन (STMicroelectronics STM32) के विभिन्न बाह्य उपकरणों की मेमोरी संरचना को परिभाषित करना शामिल है। ऐसा करने के लिए, परिणाम एक वर्ग है जिसमें कई संरचनाओं का एक संघ होता है जो सभी रजिस्टरों को परिभाषित करता है, जो लक्षित माइक्रोकंट्रोलर पर निर्भर करता है।

एक बहुत ही सरल परिधीय के लिए एक सरल उदाहरण निम्नलिखित है: एक सामान्य उद्देश्य इनपुट / आउटपुट (GPIO)

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];इस पर विचार किया है?
एमएम

3
मैं सिर्फ चेतावनी को दबा दूंगा। [class.bit] / 1 के व्यवहार की गारंटी देता है uint32_t :192;
नाथनऑलिवर 22

3
@NathanOliver मैं ख़ुशी से भी बहुत खुश हूँ, लेकिन ऐसा लगता है कि यह चेतावनी दमनकारी नहीं है (GCC का उपयोग करके) या मुझे ऐसा करने का तरीका नहीं मिला। इसके अलावा, यह अभी भी करने के लिए एक साफ तरीका नहीं है (लेकिन यह बहुत संतोषजनक होगा)। मैं सही "-W" ध्वज खोजने में कामयाब रहा, लेकिन इसे केवल अपनी फाइलों पर लागू करने का प्रबंधन नहीं किया (मैं नहीं चाहता कि उपयोगकर्ता अपने काम के लिए इस तरह की चेतावनियों को हटा दें)
J Faucher

3
BTW आप :42*32इसके बजाय:1344
एमएम

1
चेतावनियों को दबाने के लिए यह कोशिश करें? gcc.gnu.org/oniltocs/gcc/…
Hitobat

जवाबों:


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;इस स्थान पर) इसलिए मुझे इस रास्ते पर नहीं जाना पड़ेगा ...
जे फौचेर

1
@JFaucher ने अपनी लाइन काउंट आवश्यकता के लिए एक संभावित समाधान जोड़ा। यदि आपके पास ऐसी आवश्यकताएं हैं, तो आप उन सवालों का उल्लेख कर सकते हैं जो उन उत्तरों से बचने के लिए हैं जो उन्हें नहीं मिलते हैं।
क्लिफोर्ड

एडिट के लिए धन्यवाद और लाइन काउंट चीज़ न बताने के लिए खेद है। मेरा कहना है कि मेरा कोड पहले से ही गोता लगाने के लिए दर्दनाक है क्योंकि वहाँ बहुत सारी लाइनें हैं और मैं बहुत अधिक जोड़ने से बचता हूँ। इसलिए, मैं पूछ रहा था कि क्या कोई व्यक्ति "क्लीन" या "आधिकारिक" तरीका जानता था जो आसन्न अनाम बिटफील्ड (भले ही वह ठीक हो) का उपयोग करने से बचने के लिए। मैक्रो दृष्टिकोण मुझे हालांकि ठीक लगता है। वैसे, आपके उदाहरण में, आपको 36 * 32 बिट्स की जगह नहीं मिली?
जे फॉचर

@JFaucher - सही किया गया। बड़ी संख्या में रजिस्टरों के कारण I / O रजिस्टर मैपिंग फाइलें आवश्यक रूप से बड़ी हैं - आम तौर पर आप एक बार लिखते हैं, और रखरखाव एक मुद्दा नहीं है क्योंकि हार्डवेयर एक स्थिर है। यदि आप बाद में उन्हें एक्सेस करना चाहते हैं, तो "छुपा" रजिस्टरों को छोड़कर आप खुद के लिए रखरखाव का काम कर रहे हैं। आप निश्चित रूप से जानते हैं कि सभी STM32 उपकरणों में पहले से ही वेंडर द्वारा दिए गए रजिस्टर मैप हेडर हैं? इसका उपयोग करने के लिए यह कम त्रुटि वाला होगा।
क्लिफर्ड

2
मैं आपसे सहमत हूं और, निष्पक्ष होने के लिए, मुझे लगता है कि मैं आपके उत्तर में प्रदर्शित उन दो विधियों में से एक से जाऊंगा। मैं बस यह सुनिश्चित करना चाहता था कि ऐसा करने से पहले C ++ बेहतर समाधान प्रदान नहीं करता है। मुझे अच्छी तरह पता है कि एसटी उन हेडर को प्रदान करता है, हालाँकि वे मैक्रोज़ और बिटवाइज़ ऑपरेशंस के बड़े पैमाने पर उपयोग किए जाते हैं। मेरी परियोजना उन हेडर के बराबर एक C ++ का निर्माण करना है जो कम त्रुटि वाला होगा (enum classes, bitfields and so का उपयोग करके)। यही कारण है कि हम अपनी C ++ संरचनाओं में CMSIS हेडर को "ट्रांसलेट" करने के लिए एक स्क्रिप्ट का उपयोग करते हैं (और ST फाइलों में कुछ त्रुटियां मिली btw)
J Faucher

45

कैसे के बारे में एक C ++ - ish रास्ता?

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नाम स्थान के कारण आपको स्वतः पूर्णता मिलती है , और डमी पैडिंग की कोई आवश्यकता नहीं है। यहां तक ​​कि, यह अधिक स्पष्ट है कि क्या चल रहा है, जैसा कि आप प्रत्येक रजिस्टर का पता देख सकते हैं, आपको कंपाइलर के गद्दी व्यवहार पर बिल्कुल भी भरोसा करने की आवश्यकता नहीं है।


1
यह एक ही फ़ंक्शन से कई MMIO रजिस्टरों तक पहुंच के लिए एक संरचना की तुलना में कम अच्छी तरह से अनुकूलन संभव हो सकता है। एक रजिस्टर में आधार पते के लिए एक सूचक के साथ, कंपाइलर तत्काल विस्थापन के साथ लोड / स्टोर निर्देशों का उपयोग कर सकता है, जैसे ldr r0, [r4, #16], जबकि संकलक को यह याद करने की अधिक संभावना है कि प्रत्येक पते के साथ अनुकूलन अलग से घोषित किया गया है। GCC संभवतः प्रत्येक GPIO पते को एक अलग रजिस्टर में लोड करेगा। (शाब्दिक पूल से, हालांकि उनमें से कुछ को थम्ब एन्कोडिंग में तुरंत घुमाए जाने के रूप में दर्शाया जा सकता है।)
पीटर कॉर्ड्स

4
पता चला मेरी चिंताओं निराधार थे; एआरएम जीसीसी इस तरह से भी अनुकूलन करता है। godbolt.org/z/ztB7hi । लेकिन ध्यान दें कि आप चाहते हैं static volatile uint32_t &MAP0_MODER, नहीं inline। एक inlineचर संकलन नहीं करता है। ( staticसूचक के लिए किसी भी स्थिर भंडारण से बचा जाता है, और volatileवास्तव में आप MMIO के लिए चाहते हैं कि डेड-स्टोर उन्मूलन या लिखने / पढ़ने के अनुकूलन से बचने के लिए।)
पीटर कॉर्डेस

1
@PeterCordes: इनलाइन वैरिएबल एक नया C ++ 17 फीचर है। लेकिन आप सही हैं, staticइस मामले के लिए भी उतना ही अच्छा है। उल्लेख करने के लिए धन्यवाद volatile, मैं इसे अपने उत्तर में जोड़ दूंगा (और इनलाइन को स्थैतिक में बदल दूंगा, इसलिए यह पूर्व C ++ 17 के लिए काम करता है)।
जियाजा

2
यह कड़ाई से परिभाषित व्यवहार नहीं है इस ट्विटर धागे को देखें और शायद यह उपयोगी है
शफीक यघमौर

1
@JFaucher: आपके पास जितने भी नामपट्टियाँ हैं, उन्हें बनाएँ और उस नेमस्पेस में स्टैंडअलोन फ़ंक्शंस का उपयोग करें। तो, आपके पास होगा GPIOA::togglePin()
भूजा

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];  

यदि आपको संरचना, IMHO का उपयोग करना चाहिए, तो पतों को छोड़ने का सबसे अच्छा तरीका एक सदस्य को परिभाषित करना होगा और इसे एक्सेस नहीं करना होगा:

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

हमारी एक परियोजना में हमारे पास विभिन्न विक्रेताओं से स्थिरांक और संरचना दोनों हैं (विक्रेता 1 स्थिरांक का उपयोग करता है जबकि विक्रेता 2 संरचनाओं का उपयोग करता है)।


आपके उत्तर के लिए धन्यवाद। हालांकि, मैं उपयोगकर्ता के काम को आसान बनाने के लिए एक संरचना दृष्टिकोण का उपयोग करने का चयन करता हूं जब उसे एक ऑटो-पूर्ण सुविधा मिली (आपको केवल सही विशेषताएँ प्रदर्शित होंगी) और मैं उपयोगकर्ता को आरक्षित स्लॉट को "दिखाना" नहीं चाहता। मेरी पहली पोस्ट की एक टिप्पणी में बताया गया।
जे फौचर

आपके पास अभी भी ऐसा हो सकता है कि उपरोक्त पते staticको किसी संरचना का सदस्य बनाकर यह मान लिया जाए कि स्वत: पूर्ण स्थिर सदस्यों को दिखाने में सक्षम है। यदि नहीं, तो यह इनलाइन सदस्य कार्य भी हो सकता है।
Phil1970

@JFaucher मैं एक एम्बेडेड सिस्टम व्यक्ति नहीं हूँ और यह परीक्षण नहीं किया है, लेकिन स्वत: पूर्ण मुद्दे को आरक्षित सदस्य को निजी घोषित करके हल नहीं किया जाएगा? (आप एक struct में निजी सदस्यों घोषणा कर सकते हैं, और आप उपयोग कर सकते हैं public:और private:के रूप में कई बार के रूप में आप चाहते हैं, खेतों की सही आदेश प्राप्त करने के लिए।)
नथानिएल

1
@ नथानियल: ऐसा नहीं है; यदि किसी वर्ग में दोनों publicऔर privateगैर-स्थैतिक डेटा सदस्य हैं, तो यह एक मानक लेआउट प्रकार नहीं है , इसलिए यह आपके द्वारा सोचने की आदेश देने की गारंटी प्रदान नहीं करता है। (और मुझे पूरा यकीन है कि ओपी के उपयोग-मामले में एक मानक लेआउट प्रकार की आवश्यकता होती है।)
बर्बाद करें

1
volatileमेमोरी-मैप किए गए I / O रजिस्टरों के लिए उन घोषणाओं, BTW को न भूलें ।
पीटर कॉर्डेस

13

भूजा का अधिकार जिसे आप वास्तव में इसके लिए उपयोग नहीं करना चाहते हैं।

लेकिन, यदि आप जोर देते हैं, तो n बाइट्स की चौड़ाई के अप्रयुक्त सदस्य को जोड़ने का सबसे अच्छा तरीका , बस इतना करना है:

char unused[n];

यदि आप वर्ग के सदस्यों की मनमानी पैडिंग को रोकने के लिए एक कार्यान्वयन-विशिष्ट प्रागम जोड़ते हैं, तो यह काम कर सकता है।


GNU C / C ++ (gcc, clang, और अन्य जो समान एक्सटेंशन का समर्थन करते हैं) के लिए, विशेषता डालने के लिए मान्य स्थानों में से एक है:

#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");

( Godbolt संकलक एक्सप्लोरर पर उदाहरण offsetof(GPIO, b)= 7 बाइट्स दिखा रहा है ।)


9

@ क्लिफर्ड और @Adam Kotwasinski के उत्तरों पर विस्तार करने के लिए:

#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
बूस्ट सीपीपी मैक्रोज़ का उपयोग करना, मुझे लगता है कि आप सभी आवश्यक मैक्रो को हाथ से बनाने से बचने के लिए पुनरावृत्ति का उपयोग कर सकते हैं।
पीटर कॉर्डेस

3
आप उन्हें कैस्केड कर सकते हैं (पूर्वप्रक्रम पुनरावृत्ति सीमा तक, लेकिन यह आमतौर पर पर्याप्त है)। तो #define EMPTY_32_2 EMPTY_32_1; EMPTY_32_1और #define EMPTY_32_3 EMPTY_32_2; EMPTY_32_1आदि
मिरल

@PeterCordes शायद, लेकिन टैग इंगित करते हैं कि शायद बूथ C और C ++ संगतता की आवश्यकता है।
क्लिफोर्ड

2
C और C ++ समान C प्रीप्रोसेसर का उपयोग करते हैं; मुझे सी के लिए आवश्यक बढ़ावा हेडर उपलब्ध कराने के अलावा कोई समस्या नहीं दिख रही है। वे सीपीपी-मैक्रो सामान को एक अलग हेडर में डालते हैं।
पीटर कॉर्डेस

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

मुझे लगता है कि कुछ और संरचना शुरू करना फायदेमंद होगा; बदले में, spacers के मुद्दे को हल कर सकते हैं।

वेरिएंट का नाम बताइए

हालांकि फ्लैट नेमस्पेस अच्छे हैं, मुद्दा यह है कि आप खेतों के एक मोटिव संग्रह के साथ समाप्त होते हैं और सभी संबंधित क्षेत्रों को एक साथ पारित करने का कोई सरल तरीका नहीं है। इसके अलावा, एक अनाम संघ में अनाम संरचनाओं का उपयोग करके आप स्वयं ही संदर्भों को पास नहीं कर सकते हैं, या उन्हें टेम्पलेट पैरामीटर के रूप में उपयोग कर सकते हैं।

पहले कदम के रूप में, मैं, इसलिए, पर विचार करेंगे बाहर तोड़ने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);, साथ ही एक नज़र में सभी उपलब्ध आर्किटेक्चर का त्वरित अवलोकन प्राप्त कर सकता हूं ।

सरल Spacers

कई हेडर में परिभाषा विभाजन के साथ, हेडर व्यक्तिगत रूप से बहुत अधिक प्रबंधनीय हैं।

इसलिए, आपकी आवश्यकताओं को पूरा करने के लिए मेरा प्रारंभिक दृष्टिकोण दोहराया के साथ रहना होगा std::uint32_t:32;। हां, यह मौजूदा 8k लाइनों में कुछ 100s लाइनों को जोड़ता है, लेकिन चूंकि प्रत्येक हेडर व्यक्तिगत रूप से छोटा होता है, इसलिए यह उतना बुरा नहीं हो सकता है।

यदि आप अधिक विदेशी समाधान पर विचार करने को तैयार हैं, हालांकि ...

पेश है $।

यह एक छोटा ज्ञात तथ्य है जो $C ++ पहचानकर्ताओं के लिए एक व्यवहार्य चरित्र है; यह एक व्यवहार्य शुरुआती चरित्र (अंकों के विपरीत) भी है।

एक $स्रोत कोड में प्रदर्शित होने की संभावना भौहें उठाना होगा, और $$$$निश्चित रूप से कोड समीक्षा के दौरान ध्यान आकर्षित करने के लिए जा रहा है। यह कुछ ऐसा है जिसका आप आसानी से लाभ उठा सकते हैं:

#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);
};

तुम भी एक साधारण "एक प्रकार का वृक्ष" एक पूर्व प्रतिबद्ध हुक के रूप में या अपने सीआई में डाल सकते हैं जो $$$$प्रतिबद्ध C ++ कोड में दिखता है और इस तरह के कमिट्स को अस्वीकार करता है।


1
याद रखें कि ओपी का विशिष्ट उपयोग-मामला संकलक के लिए मेमोरी-मैप्ड I / O रजिस्टर का वर्णन करने के लिए है। मूल्य से पूरे ढांचे को कॉपी करने के लिए यह कभी भी समझ में नहीं आता है। (और जैसा GPIO_MAP0_MODERकि प्रत्येक सदस्य संभवतया संभव है volatile।) संभवतः पूर्व के अनाम सदस्यों का संदर्भ या टेम्पलेट-पैरामीटर उपयोग उपयोगी हो सकता है, हालांकि। और पैडिंग संरचनाओं के सामान्य मामले के लिए, सुनिश्चित करें। लेकिन उपयोग-मामला बताता है कि ओपी ने उन्हें गुमनाम क्यों छोड़ दिया।
पीटर कॉर्डेस

यदि आप $$$padding##Index_[N_];कभी भी स्वत: पूर्ण या डिबगिंग में आते हैं, तो आप फ़ील्ड का नाम अधिक आत्म-व्याख्यात्मक बनाने के लिए उपयोग कर सकते हैं । (या नामों के zz$$$paddingबाद इसे क्रमबद्ध करने के लिए GPIO..., क्योंकि ओपी के अनुसार इस अभ्यास का पूरा बिंदु मेमोरी-मैप्ड I / O स्थान नामों के लिए स्वत: पूर्ण है।)
पीटर कॉर्डेस

@PeterCordes: मैंने उत्तर को फिर से जांचने के लिए स्कैन किया, और कभी भी नकल का कोई उल्लेख नहीं देखा। मैं volatileसंदर्भ पर क्वालीफायर को भूल गया , हालांकि, जिसे सही कर दिया गया है। नामकरण के लिए के रूप में; मैं इसे ओपी तक जाने दूँगा। कई बदलाव (पैडिंग, आरक्षित, ...), और यहां तक ​​कि ऑटो-पूर्ति के लिए "सबसे अच्छा" उपसर्ग हाथ में आईडीई पर निर्भर हो सकता है, हालांकि मैं छंटाई को ट्विक करने के विचार की सराहना करता हूं।
Matthieu M.

मैं " और सभी संबंधित क्षेत्रों को एक साथ पारित करने का कोई सरल तरीका नहीं " का उल्लेख कर रहा था , जो कि संरचना असाइनमेंट की तरह लगता है, और बाकी वाक्य संघ के संरचनात्मक सदस्यों के नामकरण के बारे में है।
पीटर कॉर्डेस

1
@PeterCordes: मैं संदर्भ से गुजरने के बारे में सोच रहा था, जैसा कि बाद में सचित्र था। मुझे यह अजीब लगता है कि ओपी की संरचना उन्हें "मॉड्यूल" बनाने से रोकती है जो केवल विशिष्ट वास्तुकला (विशिष्ट का संदर्भ लेकर struct) तक पहुंचने के लिए सांख्यिकीय रूप से सिद्ध हो सकती है और यह कि unionवास्तुकला-विशिष्ट बिट्स में भी हर जगह प्रचारित किया जा रहा है दूसरों की कम परवाह कर सकता था।
Matthieu M.

0

हालांकि मैं मानता हूं कि एमसीयू I / O पोर्ट एक्सेस के लिए स्ट्रक्चर्स का उपयोग नहीं किया जाना चाहिए, मूल प्रश्न का उत्तर इस तरह दिया जा सकता है:

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

एक संरचना में सामान्य रूप से निजी और सार्वजनिक सदस्यों को मिलाकर उस मेमोरी लेआउट का परिणाम होता है जो अब C ++ मानक की गारंटी नहीं देता है। हालाँकि अगर किसी संरचना के सभी गैर-स्थैतिक सदस्य निजी हैं, तो इसे अभी भी POD / मानक लेआउट माना जाता है, और इसलिए ऐसी संरचनाएँ हैं जो उन्हें एम्बेड करती हैं।

किसी कारण से gcc एक चेतावनी उत्पन्न करता है यदि अनाम संरचना का कोई सदस्य निजी है तो मुझे इसे एक नाम देना होगा। वैकल्पिक रूप से, इसे अभी तक एक अन्य अनाम संरचना में लपेटने से चेतावनी से छुटकारा मिल जाता है (यह एक बग हो सकता है)।

ध्यान दें कि spacerसदस्य स्वयं निजी नहीं है, इसलिए डेटा अभी भी इस तरह एक्सेस किया जा सकता है:

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

हालांकि इस तरह की अभिव्यक्ति एक स्पष्ट हैक की तरह दिखती है, और उम्मीद है कि इसका उपयोग वास्तव में अच्छे कारण के बिना नहीं किया जाएगा, अकेले एक गलती के रूप में जाने दें।


1
उपयोगकर्ता किसी भी नामस्थान में पहचानकर्ताओं की घोषणा नहीं कर सकते हैं जिसमें नाम में कहीं भी अंडरस्कोर (सी ++ में, या केवल सी में शुरुआत में) है; ऐसा करने से कोड बीमार हो जाता है। ये नाम कार्यान्वयन के लिए आरक्षित हैं और इसलिए सिद्धांत रूप में आपके साथ सूक्ष्म और सूक्ष्म तरीकों से संघर्ष कर सकते हैं। वैसे भी, कंपाइलर के पास आपके कोड को बनाए रखने का कोई दायित्व नहीं है, अगर उसमें उन्हें शामिल किया जाए। ऐसे नाम आपके अपने उपयोग के लिए 'आंतरिक' नाम प्राप्त करने का एक त्वरित तरीका नहीं है।
अंडरस्कोर_ड

धन्यवाद, इसे ठीक किया।
जैक व्हाइट

-1

विरोधी समाधान।

यह मत करो: निजी और सार्वजनिक क्षेत्रों को मिलाएं।

शायद uniqie चर नाम उत्पन्न करने के लिए एक काउंटर के साथ एक मैक्रो उपयोगी होगा?

#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];
};


3
ठीक। अगर किसी को कोई फर्क नहीं पड़ता तो मैं जवाब छोड़ दूंगा कि क्या नहीं करना है।
रॉबर्ट आंद्रेजुक

4
@NicHartley उत्तर की संख्या को देखते हुए, हम एक "शोध" प्रश्न के करीब हैं। शोध में, दोषों का ज्ञान अभी भी ज्ञान है, यह दूसरों को गलत तरीके से लेने से बचता है। बहादुरी के लिए +1।
ओलिव

1
@ ओलीव और I -1 ll क्योंकि ओपी को कुछ आवश्यक था, इस उत्तर ने आवश्यकता का उल्लंघन किया, और इसलिए यह एक बुरा जवाब है। मैंने स्पष्ट रूप से किसी भी मूल्य निर्णय, सकारात्मक या नकारात्मक व्यक्ति पर, या तो टिप्पणी में नहीं किया - बस जवाब पर। मुझे लगता है कि हम दोनों सहमत हैं कि यह बुरा है। उस व्यक्ति के बारे में जो कहता है वह इस साइट के लिए ऑफ-टॉपिक है। (हालांकि एक विचार में योगदान करने के लिए कुछ समय लेने के लिए तैयार IMO कुछ सही कर रहा है, भले ही विचार पैन न हो)
फंड मोनिका का मुकदमा

2
हाँ यह गलत उत्तर है। लेकिन मुझे डर है कि कुछ लोगों को एक ही विचार आ सकता है। टिप्पणी और लिंक के कारण मैंने अभी कुछ सीखा है, यह मेरे लिए नकारात्मक बिंदु नहीं है।
रॉबर्ट एंड्रेजुक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.