2016-12-09 7 views
5

यह एक एम्बेडेड एप्लिकेशन के लिए है जो यूसी पर निम्न स्तर पर चलता है। सिस्टम के एक अन्य भाग को पैरामीटर सेट करने की आवश्यकता होती है और स्थानीय यूसी को पैरामीटर की सूची बनाए रखने की आवश्यकता होती है। प्रत्येक पैरामीटर में 8 बिट आईडी और 8 बिट मान होता है। दूसरे छोर पर स्मृति सीमाओं के कारण आईडी 0x70 पर शुरू होती है।कैसे सुनिश्चित करें कि enum और array में संकलन पर एक ही प्रविष्टियां हों?

स्मृति उपयोग को यथासंभव कम रखने के लिए मैंने पैरामीटर स्टोर को सभी लिखने योग्य मानकों के लिए आईडी और मान युक्त सरणी के रूप में कार्यान्वित किया है। फिर पैरामीटर तक पहुंचने के लिए एप्लिकेशन के अन्य हिस्सों को अनुमति देने के लिए हेडर फ़ाइल में इन पैरामीटर की एक विस्तृत सूची है।

क्या यह सुनिश्चित करने का कोई तरीका है कि enum सूची और पैरामीटर की सरणी एक ही क्रम में एक ही प्रविष्टि है? मैंने कोड को काफी अच्छी तरह से दस्तावेज किया है (सभी अर्क में शामिल नहीं हैं) लेकिन मैं यह सुनिश्चित करने के लिए संकलित समय पर कुछ प्रकार के चेक डालना चाहता हूं कि सूची और सरणी मिल जाए।

एक और चीज मुझे यकीन नहीं है कि यह इसे लागू करने का सबसे प्रभावी तरीका है। मुझे सिस्टम के दूसरे भाग में संचारित करने के लिए पैरामीटर के माध्यम से पुन: प्रयास करने में सक्षम होना चाहिए और मुझे जितनी संभव हो उतनी छोटी मेमोरी का उपयोग करने की आवश्यकता है।

parameters.h से:

/*******************************************************************************/ 
/* IDs for all parameters must be defined          */ 
/* Defaults only need to be defined for rut-time writable parameters   */ 
/* All parameters must have an ID define          */ 
/* Writable parameters must also have:           */ 
/* * DefaultValue define             */ 
/* * Entry in ParamIndex             */ 
/* * Initialesed default entry in Parameters (contained in C file)   */ 
/* * If min and max values are not 0x00 and 0xFF then define those too  */ 
/*******************************************************************************/ 

// Parameter IDs - All parameters need this defining 
#define Param_ActualTemp_ID       0xE0 
#define Param_OperationMode_ID      0xE1 
#define Param_MaintenanceModePID0_ID    0xE5 
#define Param_MaintenanceModePID1_ID    0xE6 
#define Param_FirmwareVersionL_ID     0xEB 
#define Param_FirmwareVersionH_ID     0xEC 
#define Param_SerialNumberL_ID      0xED 
#define Param_SerialNumberH_ID      0xEE 
#define Param_SerialNumberHH_ID      0xEF 
#define Param_MaxTemperature_ID      0xFC 
#define Param_NULL_ID        0xFF 

// Parameter Default Values - All writable parameters need this defining 
#define Param_NULL_DefaultValue      0xFF 
#define Param_OperationMode_DefaultValue   0 
#define Param_MaintenanceModePID0_DefaultValue  0xFF 
#define Param_MaintenanceModePID1_DefaultValue  0xFF 
#define Param_MaxTemperature_DefaultValue   0x54 

typedef struct 
{ 
    const uint8 id; 
     uint8 value; 
} PARAMETER; 

// Parameter Index, any writable parameters need an entry here 
// Used as array index for parameters[], do not edit existing values 
typedef enum 
{ 
    Param_NULL = 0, 
    Param_OperationMode, 
    Param_MaintenanceModePID0, 
    Param_MaintenanceModePID1, 
    Param_MaxTemperature, 

    /* Additional values must be entered above this line */ 
    Param_NUMBER_OF_IMPLEMENTED_PARAMS 
} ParamIndex; 

extern PARAMETER parameters[]; 

parameters.c से:

PARAMETER parameters[] = { 
    { .id = Param_NULL_ID,     .value = Param_NULL_DefaultValue}, 
    { .id = Param_OperationMode_ID,  .value = Param_OperationMode_DefaultValue}, 
    { .id = Param_MaintenanceModePID0_ID, .value = Param_MaintenanceModePID0_DefaultValue}, 
    { .id = Param_MaintenanceModePID1_ID, .value = Param_MaintenanceModePID1_DefaultValue}, 
    { .id = Param_MaxTemperature_ID,  .value = Param_MaxTemperature_DefaultValue} 
}; 

उत्तर

4

आप Param_NUMBER_OF_IMPLEMENTED_PARAMS के साथ सही रास्ते पर हैं। दुर्भाग्य से आप इसे सरणी आकार के रूप में उपयोग नहीं कर सकते हैं, क्योंकि यह केवल गारंटी देता है कि सरणी में enum की तुलना में अधिक प्रारंभकर्ता नहीं हैं। यह बहुत कम प्रारंभकर्ता वाले सरणी के खिलाफ सुरक्षा नहीं करता है।

यह सुनिश्चित करने का तरीका है कि सरणी आकार बनाम enum आकार का स्थिर दावा करना है। PARAMETER parameters[] के रूप में सरणी घोषणा रखें और फिर

_Static_assert(Param_NUMBER_OF_IMPLEMENTED_PARAMS == sizeof(parameters)/sizeof(*parameters), 
       "Array initializer list does not match enum"); 

मानक कीवर्ड _Static_assert तथापि सी 11 में ही उपलब्ध है, और मानक मैक्रो static_assert सी 11 और सी में ही उपलब्ध है ++। पुराने कंपाइलर्स पर, आपको इसे स्वयं खोजना होगा। उदाहरण के लिए:

#define STATIC_ASSERT(expr) {typedef uint8_t S_ASSERT[(expr) ? 1 : 0];} 

यह एक गुप्त दे देंगे अगर ज़ोर विफल रहता है संकलक त्रुटि "आकार शून्य के साथ एक सरणी की घोषणा नहीं कर सकते हैं"।


आदेश सरणी मदों के लिए नामित initializers का उपयोग करके यह सुनिश्चित किया जा सकता है:

PARAMETER parameters[] = { 
    [Param_NULL_DefaultValue] = { .id = Param_NULL_ID, .value = Param_NULL_DefaultValue}, 
    ... 

मनोनीत initializers डुप्लिकेट नहीं रोकता है, लेकिन डुप्लिकेट प्रविष्टियों के मामले में केवल पिछले एक का उपयोग किया जाएगा (और आप आमतौर पर एक कंपाइलर चेतावनी मिलता है)। ऐसी डुप्लिकेट प्रविष्टियां सरणी आकार को प्रभावित नहीं करती हैं।

+0

मुझे लगता है कि मेरे कंपाइलर (जीसीसी 4.1 से व्युत्पन्न) के साथ काम कर रहे एक स्थिर जोर मैक्रो को नहीं मिल रहा है, लेकिन नामित प्रारंभकर्ता यह एक अच्छा विचार है कि मुझे पता नहीं था। मैंने यह भी जोड़ा है कि मैं और मैं यह सुनिश्चित कर दूंगा कि इस परियोजना के अन्य डेवलपर को मैंने जो किया है उसके बारे में पता है। मैं शायद भविष्य में इस कोड पर रखरखाव करने वाला हूं। – RobbG

+0

@RobbG स्टेटिक आवेषण सी 11 के साथ पेश किया गया था, जो बदले में जीसीसी 4.8 के आसपास कहीं पेश किया गया था। हालांकि आप किसी भी सी संकलक पर अपने घर से बने स्थिर आवेषण मैक्रो का उपयोग करने में सक्षम होना चाहिए। – Lundin

1

आप सरणी आकार के रूप में Param_NUMBER_OF_IMPLEMENTED_PARAMS उपयोग कर सकते हैं। यदि कम से कम सरणी प्रारंभकर्ता सूची में आपके पास कई तत्व हैं तो यह कम से कम संकलक प्रतिक्रिया दे सकता है।

हालांकि चेतावनी देने के लिए कोई (मानक और पोर्टेबल) तरीका नहीं है कि आप सभी तत्वों को प्रारंभ नहीं कर रहे हैं। आपके द्वारा प्रारंभ नहीं किए जाने वाले सभी तत्व प्रारंभिक "शून्य" होंगे।

निश्चित रूप से आदेश सुनिश्चित करने का कोई तरीका नहीं है, संकलन समय पर नहीं।

स्थिर विश्लेषक उपकरण हो सकते हैं जो आपकी मदद कर सकते हैं। और निश्चित रूप से कठोर कोड-समीक्षा।

+0

धन्यवाद, मैं मुख्य रूप से यह देखने के लिए तैयार था कि ऐसा करने के तरीके में बनाया गया था। मुझे लगता है कि प्रलेखन के साथ यह स्पष्ट रूप से स्पष्ट होना चाहिए कि क्या हो रहा है और अगर हमें भविष्य में सूची बदलने की जरूरत है तो क्या जोड़ना चाहिए। मैं भविष्य में स्थैतिक विश्लेषण उपकरण देख रहा हूं, इसलिए मैं उन चीज़ों की सूची में जोड़ सकता हूं जिन्हें मैं उनके लिए देखता हूं। – RobbG

+1

बेशक आप स्थिर आवेषण के साथ संकलन समय पर यह सुनिश्चित कर सकते हैं। यह मानक ज्ञात मानक में शामिल किए जाने से पहले दशकों तक एक प्रसिद्ध परिदृश्य और कार्य-आसपास अस्तित्व में है। – Lundin

+1

@RobbG यह मेरा जवाब देखें कि इसे स्वचालित रूप से मानक सी में कैसे सुनिश्चित किया जाए। मैन्युअल समीक्षा और स्थिर विश्लेषकों की आवश्यकता नहीं है। – Lundin

1

आप इनके जैसे जनरेटर मैक्रोज़ का उपयोग कर सकते हैं।
जब आप PARAM_BLOCK को संशोधित करते हैं, तो enum और array स्वचालित रूप से निर्मित होते हैं।

#define PARAM_BLOCK(GEN_FUNC) \ 
    GEN_FUNC(Param_NULL_ID, Param_NULL_DefaultValue)   \ 
    GEN_FUNC(Param_OperationMode_ID, Param_OperationMode_DefaultValue) \ 
    GEN_FUNC(Param_MaintenanceModePID0_ID, Param_MaintenanceModePID0_DefaultValue) \ 
    GEN_FUNC(Param_MaintenanceModePID1_ID, Param_MaintenanceModePID1_DefaultValue) \ 
    GEN_FUNC(Param_MaxTemperature_ID, Param_MaxTemperature_DefaultValue) \ 

#define GENERATE_PARAM_ARRAY(paramId,paramValue) { .id = paramId, .value = paramValue }, 
#define GENERATE_PARAM_ENUM(paramId,paramValue)   paramId, 

typedef enum 
{ 
    GENERATE_PARAM_ENUM(PARAM_BLOCK) 
    /* Additional values must be entered above this line */ 
    Param_NUMBER_OF_IMPLEMENTED_PARAMS 
} ParamIndex; 

PARAMETER parameters[] = { 
    GENERATE_PARAM_ARRAY(PARAM_BLOCK) 
}; 

लेकिन शायद आप अपने पैरामीटर सरणी को सरल बना सकते हैं, क्योंकि आपके पास आईडी द्वारा ऑर्डर किया गया सरणी है, आपको आईडी की आवश्यकता नहीं है।

#define GENERATE_WRITE_PARAM_ARRAY(paramId,paramValue) paramValue, 
uint8 writeable_parameters[] = { 
     GENERATE_WRITE_PARAM_ARRAY(PARAM_BLOCK) 
    }; 
+0

मैंने इस समाधान को उद्देश्य पर टाल दिया, क्योंकि तथाकथित "एक्स मैक्रोज़" बहुत बदसूरत कोड उत्पन्न करता है। इस मामले में उनका उपयोग करने की कोई आवश्यकता नहीं होनी चाहिए। "एक्स मैक्रो" समाधान हमेशा अंतिम उपाय होते हैं और यदि संभव हो तो इससे बचा जाना चाहिए। – Lundin

संबंधित मुद्दे