यदि कंपरेंट * एरे इनिशियलाइज़ेशन कॉमा गायब है तो कंपाइलर वार्निंग जेनरेट करें


53

मैं अपने सी कोड में स्ट्रिंग शाब्दिक तालिकाओं का उपयोग कर रहा हूं। ये तालिकाएँ कमोबेश ऐसी दिखती हैं:

static const char* const stateNames[STATE_AMOUNT] =
{
    "Init state",
    "Run state",
    "Pause state",
    "Error state",
};

ऊपर दिए गए कोड के साथ समस्या यह है कि यदि तालिका लंबी हो जाती है और विकास के दौरान संशोधित हो जाती है, तो मैं समय-समय पर अल्पविराम भूल जाता हूं। कोड एक अनुपस्थित अल्पविराम के साथ एक समस्या के बिना संकलित करता है, लेकिन मेरा कार्यक्रम समाप्त हो जाता है क्योंकि अंतिम स्ट्रिंग सेट हो जाती है NULL। मैंने सत्यापित करने के लिए MinGW और Keil कंपाइलर का उपयोग किया।

अगर कॉमा गायब है तो क्या मेरे आरंभ के लिए संकलक चेतावनी उत्पन्न करने का कोई तरीका है?


1
क्या होता है जब आपका बस इस तालिका में एक राज्य जोड़ना भूल जाते हैं?
Jeroen3

1
@ Jeroen3 सच यह एक ही त्रुटि का कारण होगा। STATE_AMOUNT के विरुद्ध सूची की लंबाई का परीक्षण करने वाले एक स्थिर मुखर का उपयोग करने से यह समस्या हल हो जाती है।
जॉनी शुबर्ट

जवाबों:


62

const char*कोष्ठक की एक जोड़ी में हर लपेटकर समस्या को हल करना चाहिए जैसा कि निम्नलिखित स्निपेट में दिखाया गया है:

static const char* const stateNames[5] =
{
    ("Init state"),
    ("Run state"),
    ("Pause state")     //comma missing
    ("Pause state3"),
    ("Error state")
};

यदि आप अल्पविराम भूल जाते हैं, तो आपको इसके समान संकलन त्रुटि मिलेगी: error: called object is not a function or function pointer

लाइव डेमो


ध्यान दें कि यदि आप अल्पविराम को भूल जाते हैं कि वास्तव में क्या होता है, तो सी वास्तव में अगले अल्पविराम या सरणी के अंत तक दो (या अधिक) तार को समतल कर देगा। उदाहरण के लिए मान लें कि आप निम्नलिखित में दिखाए अनुसार अल्पविराम भूल गए हैं:

static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state" //comma missing
    "Pause state3" //comma missing
    "Error state"
};

int main(void)
{  
    printf("%s\n", stateNames[0]);
    return 0;    
}

यह वह है जो gcc-9.2उत्पन्न करता है (अन्य संकलक समान कोड उत्पन्न करते हैं):

.LC0:
        .string "Init state"
        .string "Run state"
        .string "Pause statePause state3Error state" ; oooops look what happened
        .quad   .LC0
        .quad   .LC1
        .quad   .LC2
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, OFFSET FLAT:.LC0
        mov     rdi, rax
        call    puts
        mov     eax, 0
        pop     rbp
        ret

यह स्पष्ट है कि अंतिम तीन तार संक्षिप्त हैं और सरणी जितनी लंबाई की अपेक्षा नहीं है।


33

आप कंपाइलर को सरणी को गिनने और अनपेक्षित परिणाम होने पर त्रुटि संदेश उत्पन्न कर सकते हैं:

enum { STATE_AMOUNT = 4 };

static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state"    // <--- missing comma
    "Error state",
};

_Static_assert( sizeof stateNames / sizeof *stateNames == STATE_AMOUNT,
        "oops, missed a comma" );

विचारों को लागू करने के लिए इस धागे को देखें_Static_assert कि क्या आपका कंपाइलर बहुत पुराना है और इसका समर्थन नहीं करता है।

एक बोनस के रूप में, यह तब मदद कर सकता है जब आप नए राज्य जोड़ते हैं लेकिन स्ट्रिंग तालिका को अद्यतन करना भूल जाते हैं। लेकिन आप एक्स मैक्रोज़ में भी देखना चाह सकते हैं।


धिक्कार है .... यह सटीक जवाब था मैं बस टाइप करने जा रहा था!
वेल्डर

11

मैंने हमेशा इसे हल करने के लिए स्पष्ट रूप से आकार की सरणी के संदर्भ का उपयोग किया है।

// no explicit size here
static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state",
    "Error state",
};
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;

http://coliru.stacked-crooked.com/a/593fc2eac80782a6

main.cpp:10:32: error: reference to type 'const char *const [5]' could not bind to an lvalue of type 'const char *const [4]'
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;

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

2
@ कोडीग्रे: हाँ, यह प्री-स्टैटिक-एसर था अब आप इसका उल्लेख करते हैं
मूइंग डक

9

यह आपकी मदद करने के लिए संकलक नहीं लाता है, लेकिन मुझे लगता है कि इसे नीचे की तरह लिखना संभव है, जिससे इंसानों के लिए अल्पविराम नहीं छोड़ना आसान हो जाता है:

static const char* const stateNames[STATE_AMOUNT] =
{
      "Init state"
    , "Run state"
    , "Pause state"
    , "Error state"
};

3
अंत में कुछ लागू करना आसान भी है। अल्पविराम जोड़ने के लिए आपको पिछली पंक्ति को संपादित करने की आवश्यकता नहीं है। (लापता अल्पविराम का मुख्य कारण।)
डेटाफीडलर

@datafiddler: सहमत। SQL चयन कमांड में स्तंभों की सूची को ठीक करने के लिए भी यह उपयोगी है, जब आप उनकी तारीफ कर रहे हैं और उन पर टिप्पणी नहीं कर रहे हैं। आप अक्सर अंतिम को बदलना चाहते हैं; आप शायद ही पहले बदलना चाहें। इस तरह आपको एक आइटम पर टिप्पणी करने के लिए कई लाइनों को संशोधित करने की आवश्यकता नहीं है।
जोनाथनZ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.