त्रुटि "initializer तत्व स्थिर नहीं है" जब कॉन्स्टेबल के साथ चर को इनिशियलाइज़ करने की कोशिश की जाती है


186

मुझे निम्न प्रोग्राम की लाइन 6 (my_foo को foo_init पर इनिशियलाइज़ करना) में एक त्रुटि मिलती है और मुझे यकीन नहीं है कि मुझे समझ में क्यों आता है।

typedef struct foo_t {
    int a, b, c;
} foo_t;

const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;

int main()
{
    return 0;
}

ध्यान रखें कि यह एक बड़ी, मल्टी-फाइल प्रोजेक्ट का सरलीकृत संस्करण है, जिस पर मैं काम कर रहा हूं। लक्ष्य का उद्देश्य ऑब्जेक्ट फ़ाइल में एक स्थिर होना था, जो कि कई फाइलें राज्य संरचना को आरंभीकृत करने के लिए उपयोग कर सकती थीं। चूंकि यह सीमित संसाधनों के साथ एक एम्बेडेड लक्ष्य है और संरचना इतनी छोटी नहीं है, इसलिए मुझे स्रोत की कई प्रतियां नहीं चाहिए। मैं उपयोग नहीं करना पसंद करूंगा:

#define foo_init { 1, 2, 3 }

मैं पोर्टेबल कोड लिखने का भी प्रयास कर रहा हूं, इसलिए मुझे एक समाधान की आवश्यकता है जो कि C89 या C99 मान्य है।

यह एक वस्तु फ़ाइल में ORGs के साथ क्या करना है? वह आरंभिक चर एक ORG में जाता है और दूसरे ORG की सामग्री की नकल करके आरंभ किया जाता है?

हो सकता है कि मुझे बस अपनी रणनीति बदलने की ज़रूरत हो, और स्टार्टअप पर सभी कॉपियों को एक प्रारंभिक कार्य करना होगा। जब तक कि वहाँ अन्य विचार नहीं हैं?

जवाबों:


269

सी भाषा में, स्थिर भंडारण अवधि वाले ऑब्जेक्ट्स को निरंतर अभिव्यक्तियों के साथ या एग्रीगेट इनिशियलाइज़र युक्त स्थिर अभिव्यक्तियों के साथ आरंभीकृत किया जाना है।

एक "बड़ी" वस्तु कभी भी C में स्थिर अभिव्यक्ति नहीं है, भले ही वह वस्तु घोषित हो const

इसके अलावा, सी भाषा में, शब्द "निरंतर" को संदर्भित करता शाब्दिक स्थिरांक (जैसे 1, 'a', 0xFFऔर इतने पर), enum के सदस्यों, और जैसे ऑपरेटरों के परिणाम sizeof। सी भाषा शब्दावली में कांस्टेबल-योग्य वस्तुएं (किसी भी प्रकार की) नहीं हैं । उनका उपयोग उनके प्रकार की परवाह किए बिना, स्थिर भंडारण अवधि के साथ वस्तुओं के शुरुआती में नहीं किया जा सकता है।

उदाहरण के लिए, यह एक स्थिर नहीं है

const int N = 5; /* `N` is not a constant in C */

उपरोक्त NC C ++ में एक स्थिरांक होगा, लेकिन C. में यह एक स्थिरांक नहीं है, यदि आप प्रयास करते हैं

static int j = N; /* ERROR */

आपको एक ही त्रुटि मिलेगी: एक स्थिर वस्तु को गैर-स्थिरांक के साथ आरंभ करने का प्रयास।

यही कारण है कि, सी भाषा में, हम मुख्य रूप #defineसे नामांकित स्थिरांक घोषित करने के लिए उपयोग करते हैं, और #defineएग्रीगेटर प्रारंभिक नाम बनाने के लिए भी सहारा लेते हैं ।


2
अच्छी व्याख्या के लिए +5, लेकिन आश्चर्यजनक रूप से यह कार्यक्रम ideone पर ठीक संकलन करता है: ideone.com/lx4Xed । क्या यह कंपाइलर बग या कंपाइलर एक्सटेंशन है? साभार
विध्वंसक

2
@meet: मुझे नहीं पता कि कंपाइलर ऑप्शंस का संयोजन आइडोन हुड के नीचे क्या करता है, लेकिन उनके परिणाम अक्सर विवरण से परे अजीब होते हैं। मैंने इस कोड को Coliru ( coliru.stacked-crooked.com/a/daae3ce4035f5c8b ) पर संकलित करने का प्रयास किया और मुझे C भाषा बोली सेटिंग का उपयोग किए बिना इसकी अपेक्षित त्रुटि मिली। मुझे GCC की वेब साइट पर C भाषा एक्सटेंशन के रूप में सूचीबद्ध कुछ भी दिखाई नहीं देता है। दूसरे शब्दों में, मुझे नहीं पता कि यह विचारधारा में कैसे और क्यों संकलित है। यहां तक ​​कि अगर यह एक भाषा विस्तार के रूप में संकलित करता है, तो भी इसे सी में एक नैदानिक ​​संदेश का उत्पादन करना चाहिए
एनटी

15
enum { N = 5 };का सहारा लेने के बिना स्थिरांक घोषित करने का एक अंडर-सराहनीय तरीका है #define
एमएम

2
@PravasiMeet "ideone" बस संकलक द्वारा उत्पन्न किए गए कई नैदानिक ​​संदेशों को प्रदर्शित नहीं करता है, इसलिए यह निर्धारित करने के लिए उपयोग करने के लिए एक बहुत अच्छी साइट नहीं है कि कोड सही है या नहीं।
एमएम

1
मुझे कुछ दिलचस्प पता चला है। अगर ptr एक स्थिर सूचक है जो किसी फ़ंक्शन के अंदर परिभाषित होता है, तो यह त्रुटि है: static int* ptr = malloc(sizeof(int)*5);लेकिन यह कोई त्रुटि नहीं है static int* ptr; ptr = malloc(sizeof(int)*5);:: D
aderchox

74

यह भाषा की एक सीमा है। खंड 6.7.8 / 4 में:

किसी ऑब्जेक्ट के लिए इनिशियलाइज़र के सभी भाव जिसमें स्थिर भंडारण अवधि होती है, स्थिर अभिव्यक्ति या स्ट्रिंग शाब्दिक होगा।

खंड 6.6 में, कल्पना परिभाषित करती है कि एक स्थिर अभिव्यक्ति पर क्या विचार किया जाना चाहिए। ऐसा नहीं है जहां यह कहा गया है कि एक कॉन्स्टेबल चर को एक स्थिर अभिव्यक्ति माना जाना चाहिए। यह संकलक के लिए यह ( 6.6/10 - An implementation may accept other forms of constant expressions) का विस्तार करने के लिए कानूनी है लेकिन यह पोर्टेबिलिटी को सीमित करेगा।

यदि आप बदल सकते हैं my_fooतो इसमें स्थैतिक भंडारण नहीं है, तो आप ठीक होंगे:

int main()
{
    foo_t my_foo = foo_init;
    return 0;
}

मुझे यह पसंद है कि आपने कल्पना को उद्धृत किया है, लेकिन इससे मुझे यह समझने में मदद नहीं मिलती है कि हम क्या करने वाले हैं या चीजें वैसी ही हैं जैसी वे हैं।
इवान कैरोल

1
ऐसा प्रतीत होता है कि जीसीसी 8.1 (और बाद में) ने इस उत्तर में वर्णित कुछ विस्तार को लागू किया है; यह स्वीकार करता है static const int x = 3; static int y = x;
एरिक पोस्टपिसिल

5

बस द्वारा उदाहरण के लिए की तुलना और कॉन्ट्रास्ट कोड से है http://www.geeksforgeeks.org/g-fact-80/ / कोड जीसीसी में विफल रहता है और गुजरता में g ++ /

#include<stdio.h>
int initializer(void)
{
    return 50;
}

int main()
{
    int j;
    for (j=0;j<10;j++)
    {
        static int i = initializer();
        /*The variable i is only initialized to one*/
        printf(" value of i = %d ", i);
        i++;
    }
    return 0;
}

2

यह थोड़ा पुराना है, लेकिन मैं एक समान मुद्दे में भाग गया। यदि आप एक पॉइंटर का उपयोग करते हैं तो आप ऐसा कर सकते हैं:

#include <stdio.h>
typedef struct foo_t  {
    int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
    const foo_t *const f1 = &s_FooInit;
    const foo_t *const f2 = s_pFooInit;
    printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
    printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
    return 0;
}

5
मुझे स्टैटिक स्टोरेज अवधि के साथ एक वैरिएबल दिखाई नहीं देता है, जो यहां एक गैर-स्थिर द्वारा इनिशियलाइज़ किया गया है।
गुडबाय एसई

0

gcc 7.4.0 नीचे दिए गए कोड को संकलित नहीं कर सकता है:

#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
    printf("%s - %s\n", str1, str2);
    return 0;
}

constchar.c: 3: 21: एरर: इनिशियलाइज़र एलिमेंट कॉन्स्टेंट कॉस्ट चार * str2 = str1 नहीं है;

वास्तव में, एक "कॉस्ट चार *" स्ट्रिंग एक संकलन-समय स्थिर नहीं है, इसलिए यह एक इनिशियलाइज़र नहीं हो सकता है। लेकिन एक "कास्ट चार * कास्ट" स्ट्रिंग एक संकलन-समय स्थिर है, यह एक इनिशियलाइज़र होने में सक्षम होना चाहिए। मुझे लगता है कि यह क्लैंग का एक छोटा सा दोष है।

एक फ़ंक्शन नाम निश्चित रूप से एक संकलन-समय स्थिरांक है। यदि यह कोड काम करता है:

void func(void)
{
    printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
    f();
    return 0;
}

आपके द्वारा पोस्ट किए गए कोड में, 6.7.9 इनिशियलाइज़ेशन , पैरा 4 के अनुसार str1कोई अभिव्यक्ति नहीं है : "किसी ऑब्जेक्ट के लिए इनिशियलाइज़र के सभी एक्सप्रेशन जिसमें स्थिर या थ्रेड स्टोरेज अवधि होती है, लगातार एक्सप्रेशन या स्ट्रिंग लिटरल होंगे।"
एंड्रयू हेनले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.