Nima uchun int x [n] noto'g'ri nostaliyaning qiymatiga ega?

Buni nima uchun noto'g'ri qilishni tushunmayman:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

hatto n allaqachon const qiymati.

Buni amalga oshirishda GNU derleyici uchun to'g'ri ko'rinadi:

const int n = 5;
int x[n]; /*without initialization*/

Men C99 ning VLA xususiyatidan xabardorman va shunga qaramay, nima sodir bo'layotganiga bog'liq Faqat fonda nima sodir bo'layotganini aniq tushuntirish kerak.

37
Bu savol c99 bilan bog'liq. Tegni olib tashlamang.
qo'shib qo'ydi muallif haccks, manba
n ta'rifi bo'yicha static ga bog'lansangiz, u ishlaydi; static const haqiqiy global kompilyatsiya doim sobit bo'ladi, balki sobit saqlanadigan stack emas.
qo'shib qo'ydi muallif ShadowRanger, manba
@JensGustedt: Makrolar sog'lom kontseptsiyadan oldin o'yinga kiritilishidan oldin amalga oshirilgan matn sifatida almashtirilgani bois, siz ularni nazarda tutmasligingizga aminman. Lekin men bir narsani unutganimga xursandman. Turi uchun: ishonch emas; enum : uint8_t { turi va barcha sobit uint8_t kengaytmasi bo'lib, oddiy enum { IMO-ning har qanday narsani ko'tarish, lekin ularni juda foydali qilish, masalan ko'milgan dasturlash uchun va ushbu "buzuq" #define larning ko'pini xavfsiz saqlaydi.
qo'shib qo'ydi muallif Olaf, manba
@ShadowRanger: C C ++ emas. const ning semantikasi farqlardan biridir. C belgisi sog'lom emas. Masalan, 1 C standartidagi integer doimiy dir. const int i hali ham o'zgaruvchan!
qo'shib qo'ydi muallif Olaf, manba
const faqatgina siz so'zini derazaga beradigan, lekin to'g'ridan-to'g'ri yoki bilvosita o'zgaruvchini o'zgartirmaydigan so'zdir. Birinchi eng kompilyatorlar uchun ogohlantiriladi, chunki ikkinchisiga (masalan, ko'rsatkichlar orqali) barcha mumkin bo'lgan buzilishlarni aniqlashda juda cheklangan. Agar kontraktni buzsangiz, siz aniqlanmagan xatti-harakatni taklif qilasiz.
qo'shib qo'ydi muallif Olaf, manba
@JensGustedt: Ha, men bularni har doim unutganman. Ular ba'zi bir maxsus turlardir, asosan ularning turini aniq belgilay olmaysiz (C11 da C ++ 11 dan kodni enum ni nihoyat foydaliroq qilish kerak). Va foydalanuvchi tomonidan aniqlanmagan _True va _False ikkita "boolean" sobit. Hmm, siz ham "boshqacha" degan so'zlarni yozganingizdek, boshqalar ham bor: boshqa foydalanuvchi belgilanadigan ramziy barqarorlarni men unutganmisiz? (jiddiy savol, men oddiy narsalarni unutgan bo'lardim - agar o'rmonda bo'lsangiz, daraxtlarni ko'rasiz)
qo'shib qo'ydi muallif Olaf, manba
@JensGustedt: _True haqida ... Hmm, men ular mavjud bo'lgan qasamyod etar edim. Lekin siz to'g'ri va bu haqda o'ylayapsiz, C _Bool da C ++ dan farqli o'laroq, aslida kimmeriyadir. Men, albatta, ular C99 (qisman) bilan qilganidek, ular jasoratli narsalarni yo'q qilishni istashlarini istardim. Bu narsalarsiz C juda kamroq chalkashlik bilan juda yaxshi til bo'lishi mumkin edi.
qo'shib qo'ydi muallif Olaf, manba
@JensGustedt: har doim emas. Birgalikda topshiriqlarni o'z ichiga olgan topshiriqlarni o'ylab ko'ring. Ichki tizimlarda odatda PORTA | = MYBITMASK kabi narsalar mavjud. Holbuki, bu narsa avval int ga kengaytirilishi mumkin bo'lsa-da, derleyici yana bir necha turdagi tekshiruvni amalga oshirishi mumkin. Xuddi shunday ma'lumotlarni RAM bilan cheklangan tizimda struct da saqlashga o'xshash. Hatto bo'lmasa ham, nima uchun uni kengaytirish o'rniga kengroq turlarga ruxsat berish kerak?
qo'shib qo'ydi muallif Olaf, manba
@JordanMelo: Fikringiz ham aniq emas. "Agar siz kontraktni buzsangiz, aniqlanmagan xatti-harakatlarni taklif qilasiz". - Optimizatsiya haqida gapirmaganman. Mening nuqtaim const ning semantikasida mavjud bo'lsa, masalan, Paskal yoki C ++ kabi boshqa tillardan kutishadi. const da restrict ga o'xshash bir tanlov. Ham derleyici uchun kodni optimallashtirish uchun muayyan xatti-harakatni bajarishi mumkin, lekin majburiy emas. Standartga murojaat qiling.
qo'shib qo'ydi muallif Olaf, manba
@Olaf, men nima uchun kodni int ga qaraganda ancha tor bo'lgan turlarga ega bo'lish uchun foydali bo'lar edi. Deyarli har qanday sharoitda bular int ga ko'tariladi. Keyinchalik qiziqroqroq narsa yanada kengroq.
qo'shib qo'ydi muallif Jens Gustedt, manba
@Olaf, ehtimol, bu g'alati qoidani qo'ldan boy bergan bo'lardim, agar siz makrolar uchun hisob bermasangiz, bu ulardagina. enum S da har doim int bo'lib, narsalarni buzmasdan C ++ 11 bilan bir xil yo'lga o'tish qiyin bo'lar edi. (Va _True yoki _False kabi narsalar mavjud emas. Faqat true so'l va FALSE da 1 va 0 ni tanlang.)
qo'shib qo'ydi muallif Jens Gustedt, manba
@Olaf, C bir necha ramziy sobit bor, ehtimol ularni kutmasligingiz mumkin, ya'ni raqamlar.
qo'shib qo'ydi muallif Jens Gustedt, manba
@Olaf Agar const o'zgaruvchisini markerlar bilan o'zgartiradigan bo'lsak, derazangizni const so'zingizga kiritishni va kompilyatsiya vaqtida n har doim 5ga baholanadi. Axir u allaqachon aniqlanmagan xatti-harakatlaringizni o'zingizning mas'uliyatingizga aylantiradi. Shuning uchun men sizning maqsadingiz nima ekanini bilmayman.
qo'shib qo'ydi muallif Jordan Melo, manba
@hacks bu savolni emas, balki standart qayta ko'rib chiqish bilan aniq bog'liq. Yorliq butunlay ahamiyatsiz.
qo'shib qo'ydi muallif Leushenko, manba

5 javoblar

Eslash kerak bo'lgan asosiy narsa const va "constant" ikkita juda farqli narsani anglatadi.

const kalit so'zi, albatta, "faqat o'qish" degan ma'noni anglatadi. doimiy 42 yoki 1.5 (yoki numaralandırma yoki belgi sobit) kabi raqamli harfdir. Agar doimiy ifoda , 2 + 2 kabi kompilyatsiya vaqtida baholanadigan alohida turdagi ifodadir.

Shunday qilib, deklaratsiya berildi:

const int n = 5;

n iborasi ob'ektining qiymatini anglatadi va u doimiy ifoda sifatida ko'rib chiqilmaydi. Odatda, bir derleyici n ga mos yozuvni optimallashtiradi, uni kodi 5 uchun ishlatiladigan kod bilan almashtiradi, lekin bu shart emas - va ifodasi constant joriy kompilyatorning donoligi bilan emas, balki til bilan aniqlanadi.

const (o'qish uchun) va constant (kompilyatsiya vaqtida baholangan) o'rtasidagi farqning misoli:

const size_t now = time(NULL);

const kalit so'zi, uni ishga tushirgandan so'ng now qiymatini o'zgartirishga ruxsat berilmagan degan ma'noni anglatadi, lekin time (NULL) qiymati aniq aniq emas ish vaqtiga qadar hisoblash.

Shunday qilib:

const int n = 5;
int x[n];

const kalit so'zidan tashqari, Cda joriy bo'lmaydi.

tili (va IMHO ehtimol bo'lishi kerak) n ni doimiy ifoda sifatida baholashi mumkin; faqat shu tarzda aniqlanmagan. (C ++ kabi qoidalar mavjud, C ++ standartiga yoki talon-taroj uchun yaxshi ma'lumotga qarang.)

Agar 5 qiymatiga ega nom berilgan bir doimiylikni istasangiz, eng keng tarqalgan usul makroni aniqlashdir:

#define N 5
int x[N];

Yana bir yondashuv - ro'yxatga olishning doimiyligini aniqlash:

enum { n = 5 };
int x[n];

Nomerlangan sobit - doimiy iboralar va har doim ham int turidagi (bu usul int dan boshqa turdagi ishlamaydi degan ma'noni anglatadi). Va, ehtimol, enum mexanizmini suiiste'mol qilish.

1999 standartidan boshlab, bir qator doimiy bo'lmagan o'lcham bilan aniqlanishi mumkin; bu VLA yoki o'zgarmaydigan uzunligi qatori. Bunday qatorlarga faqat blok doirada ruxsat beriladi va boshlang'ichlar bo'lmasligi mumkin (chunki derleyici boshlang'ich elementlarning to'g'ri soniga ega ekanligini tekshira olmaydi).

Biroq, asl kodingizni kiriting:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

derleyici boshlang'ichdan uzunlikni bo'shatishga ruxsat berishingiz mumkin:

int x[] = { 1,1,3,4,5 };

Keyinchalik qatorni o'lchamidan hisoblashingiz mumkin:

const int x_len = sizeof x/sizeof x[0];
35
qo'shib qo'ydi
"Doimiy raqamli tom ma'noda". Bu qat'iymi? Boshqa turdagi turg'unlar bo'lishi kerakmi?
qo'shib qo'ydi muallif artm, manba
@underscore_d: Ha, C ++ qoidasi biroz murakkab - lekin bu muayyan holatda qo'llaniladi. Men bir necha so'zlarni qo'shib qo'ydim.
qo'shib qo'ydi muallif Keith Thompson, manba
@artm: Siz haqsiz, Cda to'rt xil turg'unlik mavjud: integer, suzuvchi, ro'yxatga olish va belgilar.
qo'shib qo'ydi muallif Keith Thompson, manba
OT, lekin: "C ++ ning bunday qoidasi bor [kodni n kodini baholash uchun doimiy ibora]". Xo'sh, faqat ba'zan; Bu so'zni chindan ham aniq qilish uchun constexpr ni almashtirishingiz kerak. Faqat const dan foydalanish ba'zi holatlarda ishlashi mumkin, ammo kontekstga qarab C ++ da "doimiy ifoda" berilishini kafolatlamaydi. Masalan: stackoverflow.com/questions/18996258/& hellip;
qo'shib qo'ydi muallif underscore_d, manba

n - bu const qiymati bo'lsa, int x [n] nima uchun noto'g'ri?

n is not a constant. const only promise that n is a 'read-only' variable that shouldn't be modified during the program execution.
Note that in , unlike , const qualified variables are not constant. Therefore, the array declared is a variable length array.
You can't use initializer list to initialize variable length arrays.

C11-§6.7.9/3:

Boshlanadigan ob'ekt turi noma'lum hajmli yoki to'liq bo'lmagan ob'ekt turi bo'lishi kerak, ya'ni o'zgarmaydigan uzunlik qatori turi emas. .

n qilish uchun #define yoki enum

#define n 5
int x[n] = { 1,1,3,4,5 };   
21
qo'shib qo'ydi
@haccks - banklar. Shunday qilib #define dan foydalanib, biz har qanday turdagi (raqamli/int/juft/etc, char, string) xabar berishimiz mumkin. enum dan foydalanib, u int sobit bo'lishi kerak.
qo'shib qo'ydi muallif artm, manba
@hacks qiziq - const doimiy emas. Shunday qilib, C da bitta kodni faqatgina #define orqali amalga oshirish mumkinmi?
qo'shib qo'ydi muallif artm, manba
@cpplearner; o__O. Fikringiz uchun rahmat. Hech qachon buni bilmas edim.
qo'shib qo'ydi muallif haccks, manba
@artm; Ha, aniq.
qo'shib qo'ydi muallif haccks, manba
@artm; Siz #define yoki enum dan foydalanishingiz mumkin.
qo'shib qo'ydi muallif haccks, manba
Eslatma: C ++ da, const -qualified variables doimiy so'zlar bo'lishi mumkin yoki bo'lmasligi mumkin, masalan. const int n = rand ()% 5; int x [n]; C da to'g'ri emas, balki C ++ da!
qo'shib qo'ydi muallif M.M, manba
@Oval - To'g'ri, bu OSh uchun noto'g'ri yo'l-yo'riq ko'rsatildi.
qo'shib qo'ydi muallif chux, manba
n - bu o'zgaruvchi, u const , lekin u emas. const samarali tarzda C.da o'qish uchun ishlatiladi.
qo'shib qo'ydi muallif chux, manba
Lekin n o'zgaruvchan emas.
qo'shib qo'ydi muallif Yahia Farghaly, manba
@artm: C standarti boshqa tillardagi "litals" deb ataladigan "doimiy" atamasini qo'llaydi ("string literals" juda yaxshi bo'lgani uchun bu izchil emas). const - bu faqat restrict yoki volatile kabi saralash. Boshqa saralashchilarga o'xshab, kompilyatorga foydalanish haqida ba'zi taxminlar kiritishga ruxsat beriladi, ammo talab qilinmaydi.
qo'shib qo'ydi muallif Olaf, manba
@chux: Aslida, faqat o'qish uchun kafolatlangan emas. Bu dasturchi tomonidan faqatgina kompilyatorga kafolat. Derleyici barcha qoidabuzarlarni aniqlay olmaydi, yoki ish vaqti muhiti talab qilinmaydi.
qo'shib qo'ydi muallif Olaf, manba
const int n = 5; int x [n]; C ++ da ishlaydi, lekin int m = 5; const int n = m; int x [n]; kiritilmaydi. Ha, bu shoshqaloq :-)
qo'shib qo'ydi muallif cpplearner, manba
@artm Ha, chunki #define ko'rsatmasi bilan oldingi protsessor kodni kompilyatorga uzatmasdan oldin o'zgartiradi. Compiler hech qachon sizning belgilangan doimiyligini hech qachon ko'rmaydi, faqat uning qiymatini ko'radi
qo'shib qo'ydi muallif Taelsin, manba

Agar siz qatorni to'liq ishga tushiradigan bo'lsangiz, derazaveringan qatorni kattalashtirishga ruxsat berish osonroq, xavfsizroq va yanada qulay bo'lishi mumkin:

int x[] = { 1,1,3,4,5 };
const int n = sizeof(x)/sizeof(*x) ; 

Keyin qatorni o'lchamini o'zgartirish uchun faqat boshlanuvchilar ro'yxatini o'zgartirish kerak, balki va hajmini o'zgartirish uchun boshlang'ich ro'yxatini o'zgartirmang. Juda ko'p boshlanuvchilar bo'lsa, ayniqsa foydali.

7
qo'shib qo'ydi

Agar n const bo'lsa-da, uni VLA yaratmoqchi bo'lmaguningizcha, uning hajmini aniqlash uchun foydalana olmaysiz. Biroq, VLA ishga tushirish uchun boshlang'ich ro'yxatidan foydalana olmaysiz.

Ruxsat etilgan o'lchamli qatorni yaratish uchun so'ldan foydalaning.

#define ARRAY_SIZE 5

int x[ARRAY_SIZE] = { 1,1,3,4,5 };
3
qo'shib qo'ydi
Hmm, bu jiddiy maslahat bo'la olmaydi; bu global belgilar majmuasini ifloslantirmaydi, potentsialni ifodalaydi va xatolarni aniqlash juda qiyin, faqat o'lchamli kattalik yaratish uchun.
qo'shib qo'ydi muallif Sebastian Mach, manba
@ underscore_d, n dan foydalanish illyustratsion maqsadlar uchun ishlatilgan, ammo yaxshi bajarilganligini ko'rsatish.
qo'shib qo'ydi muallif R Sahu, manba
@chux: Sizda statik VLA bo'lishi mumkin emas.
qo'shib qo'ydi muallif Olaf, manba
Ugh. Ismni o'zgartirish uchun bezovta qilmaslik bu dahshatli tavsiyani keltirib chiqaradi. Har kim, iltimos, iltimos, bu kabi har qanday makroyu nomlamang. Faqatgina bitta harfni, ayniqsa, ayniqsa juda keng tarqalgan n nomini olib tashlash natijasida paydo bo'lishi mumkin bo'lgan dahshatni tasavvur qiling. Makroslar (yoki ulardan kamida 99,9%) ularni qiyinlashtiradi va (ab) foydalanishni istamaslik uchun HUGE_SHOUTY_AND_UGLY_NAMES , aniq bo'lishi kerak.
qo'shib qo'ydi muallif underscore_d, manba
Blok yoki funktsiya doirasida doimiylikni saqlamoqchi bo'lsangiz, ro'yxatdagi doimiylik ham bajaradi: enum {n = 5}; int x [n] = {1,1,3,4,6};
qo'shib qo'ydi muallif Ian Abbott, manba

Kodingiz bu erda myfunc() dan semantik jihatdan farq qiladimi:

void myfunc(const int n) { 
    int x[n] = { 1,1,3,4,5 };
    printf("%d\n", x[n-1]);
    *( (int *) &n) = 17;   // Somewhat less "constant" than hoped...
    return ;
}

int main(){
    myfunc(4);
    myfunc(5);
    myfunc(6); // Haven't actually tested this.  Boom?  Maybe just printf(noise)?
    return 0;
}

n , albatta, bu har doim ham bormi? Derleyici, x [] uchun ajratilgan joyni qanchalik bo'sh joy deb hisoblaysiz (buni bajarish uchun derivat ishi)?

Boshqalar ta'kidlaganidek, cv-qualifier const emas, balki "derleme vaqtida va har doim uchun doimiy qiymatni" bildiradi. Bu "mahalliy kodning o'zgarishi kerak emasligi (u mumkin bo'lsa ham)" degan ma'noni anglatadi.

2
qo'shib qo'ydi