C99 da yuzaga kelishi mumkin bo'lgan doimiy ifodalangan dastlabki instruktor

Bu haqiqiy C99 kodmi? Agar shunday bo'lsa, u dasturni aniqlagan xatti-harakatni belgilaydimi?

int a;
unsigned long b[] = {(unsigned long)&a+1};

C99 standarti tushunchasidan, ISO C99 standartidagi §6.6 dan, bu to'g'ri bo'lishi mumkin:

  1. An integer constant expression shall have integer type and shall only have operands that are integer constants (...) Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.

  2. More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

    • an arithmetic constant expression,
    • (...)
    • an address constant for an object type plus or minus an integer constant expression.

Shu bilan birga, qo'shimcha to'ldirish ehtimoli mavjudligi sababli, bu doimiy ifodalash hisoblanmaydi va shuning uchun joriy C99 kod emas.

Agar kimdir mening fikrim to'g'ri ekanini tasdiqlasaydimi?

Esda tutingki, GCC va Clang bu kodni ogohlantirishsiz, hatto -std = c99 -passantic dan foydalangan holda qabul qiladi. Biroq, unsigned long o'rniga unsigned int uchun, ya'ni, quyidagi kodni ishlatib:

int a;
unsigned long b[] = {(unsigned int)&a+1};

Keyin ikkala kompilyator ham ifoda derazadan vaqtni sobit emas deb shikoyat qiladilar.

6
Fayl hajmida yoki blok doirada buni nazarda tutyapsizmi?
qo'shib qo'ydi muallif M.M, manba
Fayl hajmida yoki blok doirada buni nazarda tutyapsizmi?
qo'shib qo'ydi muallif M.M, manba
Fayl hajmida yoki blok doirada buni nazarda tutyapsizmi?
qo'shib qo'ydi muallif M.M, manba
Menimcha, uzun o'rniga int uchun tovoq (yoki aniqlanmagan xatti-harakat) olib kelishi mumkin, chunki kompilyatorlar uni "doimiy ifoda emas" deb rad etdilar; shuning uchun ham ular birinchi masala bo'yicha xuddi shu mantiqni qo'llashi va uni rad etishni o'ylab topdim.
qo'shib qo'ydi muallif anol, manba
Menimcha, uzun o'rniga int uchun tovoq (yoki aniqlanmagan xatti-harakat) olib kelishi mumkin, chunki kompilyatorlar uni "doimiy ifoda emas" deb rad etdilar; shuning uchun ham ular birinchi masala bo'yicha xuddi shu mantiqni qo'llashi va uni rad etishni o'ylab topdim.
qo'shib qo'ydi muallif anol, manba
Menimcha, uzun o'rniga int uchun tovoq (yoki aniqlanmagan xatti-harakat) olib kelishi mumkin, chunki kompilyatorlar uni "doimiy ifoda emas" deb rad etdilar; shuning uchun ham ular birinchi masala bo'yicha xuddi shu mantiqni qo'llashi va uni rad etishni o'ylab topdim.
qo'shib qo'ydi muallif anol, manba
Ushbu o'zgaruvchilar fayllar miqyosida e'lon qilingan (global sifatida).
qo'shib qo'ydi muallif anol, manba
Ushbu o'zgaruvchilar fayllar miqyosida e'lon qilingan (global sifatida).
qo'shib qo'ydi muallif anol, manba
Ushbu o'zgaruvchilar fayllar miqyosida e'lon qilingan (global sifatida).
qo'shib qo'ydi muallif anol, manba
To'lqinlarning to'liq ifodasi uni doimiy ifodadan o'chirmasligini qaerda aytadi?
qo'shib qo'ydi muallif unwind, manba
To'lqinlarning to'liq ifodasi uni doimiy ifodadan o'chirmasligini qaerda aytadi?
qo'shib qo'ydi muallif unwind, manba
To'lqinlarning to'liq ifodasi uni doimiy ifodadan o'chirmasligini qaerda aytadi?
qo'shib qo'ydi muallif unwind, manba
"a" ning ikkinchi baytining 'manzilini' sizning qatoriga tayinlash. Agar unda uzoq imzolangan int majmuasini kiritishda xatolik yuz berishi mumkin.
qo'shib qo'ydi muallif user3629249, manba
"a" ning ikkinchi baytining 'manzilini' sizning qatoriga tayinlash. Agar unda uzoq imzolangan int majmuasini kiritishda xatolik yuz berishi mumkin.
qo'shib qo'ydi muallif user3629249, manba
"a" ning ikkinchi baytining 'manzilini' sizning qatoriga tayinlash. Agar unda uzoq imzolangan int majmuasini kiritishda xatolik yuz berishi mumkin.
qo'shib qo'ydi muallif user3629249, manba

9 javoblar

Shu munosabat bilan ishlab chiquvchilar shu kabi masala ustida ishlaydilar: Funktsiya pointer uzoq, lekin int emas, balki qachon kompilyatsiya doim sobit? mantiqiy asos bu kompilyatorni qo'llab-quvvatlashni talab qilmaydi ( ushbu stsenariy 6.6p7 dagi har qanday o'qga kiritilmagan) va bu qo'llab-quvvatlanadigan qisqartirilgan manzillarni qo'llab quvvatlashga ruxsat berilsa-da,

I assume that sizeof(int) < sizeof(void(*)()) == sizeof(long) on your target. The problem is that the tool chain almost certainly can't express a truncated address as a relocation.

C only requires the implementation to support initializer values that are either (1) constant binary data, (2) the address of some object, or (3) or an offset added to the address of some object. We're allowed, but not required, to support more esoteric things like subtracting two addresses or multiplying an address by a constant or, as in your case, truncating the top bits of an address away. That kind of calculation would require support from the entire tool chain from assembler to loader, including various file formats along the way. That support generally doesn't exist.

Agar tamsayı turiga ko'rsatgich yuboradigan ishingiz 6.6 paragrafi 7 ostidagi vaziyatlardan biriga mos kelmasa:

Boshlang'ichlarda doimiy iboralar uchun ko'proq kenglik beriladi.   Bunday turg'un ifoda ifodalaridan biri bo'lishi kerak   quyidagi:

     
      
  • arifmetik sobit ifoda,
  •   
  • noyob ko'rsatgichning doimiyligi,
  •   
  • bir manzil doimiy yoki
  •   
  • Ob'ekt turi uchun manzil doimiyligi ortiqcha yoki butun sonni doimiy ifodadan o'chiradi.
  •   

ammo post derleyici ichida aytilganidek, doimiy ifodalarning boshqa shakllarini qo'llab-quvvatlashga ruxsat beriladi:

Ilova doimiy ifodalarning boshqa shakllarini qabul qilishi mumkin.

lekin bu clang yoki gcc buni qabul qilmaydi.

3
qo'shib qo'ydi

Shu munosabat bilan ishlab chiquvchilar shu kabi masala ustida ishlaydilar: Funktsiya pointer uzoq, lekin int emas, balki qachon kompilyatsiya doim sobit? mantiqiy asos bu kompilyatorni qo'llab-quvvatlashni talab qilmaydi ( ushbu stsenariy 6.6p7 dagi har qanday o'qga kiritilmagan) va bu qo'llab-quvvatlanadigan qisqartirilgan manzillarni qo'llab quvvatlashga ruxsat berilsa-da,

I assume that sizeof(int) < sizeof(void(*)()) == sizeof(long) on your target. The problem is that the tool chain almost certainly can't express a truncated address as a relocation.

C only requires the implementation to support initializer values that are either (1) constant binary data, (2) the address of some object, or (3) or an offset added to the address of some object. We're allowed, but not required, to support more esoteric things like subtracting two addresses or multiplying an address by a constant or, as in your case, truncating the top bits of an address away. That kind of calculation would require support from the entire tool chain from assembler to loader, including various file formats along the way. That support generally doesn't exist.

Agar tamsayı turiga ko'rsatgich yuboradigan ishingiz 6.6 paragrafi 7 ostidagi vaziyatlardan biriga mos kelmasa:

Boshlang'ichlarda doimiy iboralar uchun ko'proq kenglik beriladi.   Bunday turg'un ifoda ifodalaridan biri bo'lishi kerak   quyidagi:

     
      
  • arifmetik sobit ifoda,
  •   
  • noyob ko'rsatgichning doimiyligi,
  •   
  • bir manzil doimiy yoki
  •   
  • Ob'ekt turi uchun manzil doimiyligi ortiqcha yoki butun sonni doimiy ifodadan o'chiradi.
  •   

ammo post derleyici ichida aytilganidek, doimiy ifodalarning boshqa shakllarini qo'llab-quvvatlashga ruxsat beriladi:

Ilova doimiy ifodalarning boshqa shakllarini qabul qilishi mumkin.

lekin bu clang yoki gcc buni qabul qilmaydi.

3
qo'shib qo'ydi

Shu munosabat bilan ishlab chiquvchilar shu kabi masala ustida ishlaydilar: Funktsiya pointer uzoq, lekin int emas, balki qachon kompilyatsiya doim sobit? mantiqiy asos bu kompilyatorni qo'llab-quvvatlashni talab qilmaydi ( ushbu stsenariy 6.6p7 dagi har qanday o'qga kiritilmagan) va bu qo'llab-quvvatlanadigan qisqartirilgan manzillarni qo'llab quvvatlashga ruxsat berilsa-da,

I assume that sizeof(int) < sizeof(void(*)()) == sizeof(long) on your target. The problem is that the tool chain almost certainly can't express a truncated address as a relocation.

C only requires the implementation to support initializer values that are either (1) constant binary data, (2) the address of some object, or (3) or an offset added to the address of some object. We're allowed, but not required, to support more esoteric things like subtracting two addresses or multiplying an address by a constant or, as in your case, truncating the top bits of an address away. That kind of calculation would require support from the entire tool chain from assembler to loader, including various file formats along the way. That support generally doesn't exist.

Agar tamsayı turiga ko'rsatgich yuboradigan ishingiz 6.6 paragrafi 7 ostidagi vaziyatlardan biriga mos kelmasa:

Boshlang'ichlarda doimiy iboralar uchun ko'proq kenglik beriladi.   Bunday turg'un ifoda ifodalaridan biri bo'lishi kerak   quyidagi:

     
      
  • arifmetik sobit ifoda,
  •   
  • noyob ko'rsatgichning doimiyligi,
  •   
  • bir manzil doimiy yoki
  •   
  • Ob'ekt turi uchun manzil doimiyligi ortiqcha yoki butun sonni doimiy ifodadan o'chiradi.
  •   

ammo post derleyici ichida aytilganidek, doimiy ifodalarning boshqa shakllarini qo'llab-quvvatlashga ruxsat beriladi:

Ilova doimiy ifodalarning boshqa shakllarini qabul qilishi mumkin.

lekin bu clang yoki gcc buni qabul qilmaydi.

3
qo'shib qo'ydi

Ushbu kodni muvofiq bajarish bilan qabul qilinishi shart emas. Sizning savolingizga tegishli pasportni keltirdingiz:

  1. More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
    • an arithmetic constant expression,
    • a null pointer constant,
    • an address constant, or
    • an address constant for an object type plus or minus an integer constant expression.

(unsigned long)&x is none of those things. It's not an arithmetic constant because of C11 6.6/8:

Aritmetik sobit ifodada konveyer operatorlari faqatgina konvertatsiya qilishlari kerak   arifmetik turlarini arifmetik turlarga ajratish.

(markerlarning arifmetik turlari emas, 6.2.5/18); va manzil doimiy emas, chunki barcha manzil sobit belgilar (6.6/9). Nihoyat, markerni ortiqcha yoki minus import bilan ishora qiladi, shuning uchun bu ham emas.


Biroq, 6.6/10, dastur, doimiy ifodalarning boshqa shakllarini qabul qilishi mumkinligini aytadi. Bu asl kodni noto'g'ri shakllangan deb atash kerakmi yoki yo'qmi (noto'g'ri kod diagnostika talab qiladimi) degan ishonchim yo'q. Shubhasiz sizning kompilyatoringiz bu erda boshqa doimiy iboralarni qabul qilmoqda.


Keyingi masala shundan iboratki, markerdan tamsayinga chiqish amaliyotda aniqlanadi. Muayyan ko'rsatgichga mos keladigan aniq raqam bo'lmasa, u ham aniqlanmasligi mumkin. (6.3.2.3/6)

Finally, the + 1 on the end makes no difference. unsigned long arithmetic is well-defined on addition and subtraction, so it is OK if and only if (unsigned long)&x is OK.

2
qo'shib qo'ydi

Ushbu kodni muvofiq bajarish bilan qabul qilinishi shart emas. Sizning savolingizga tegishli pasportni keltirdingiz:

  1. More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
    • an arithmetic constant expression,
    • a null pointer constant,
    • an address constant, or
    • an address constant for an object type plus or minus an integer constant expression.

(unsigned long)&x is none of those things. It's not an arithmetic constant because of C11 6.6/8:

Aritmetik sobit ifodada konveyer operatorlari faqatgina konvertatsiya qilishlari kerak   arifmetik turlarini arifmetik turlarga ajratish.

(markerlarning arifmetik turlari emas, 6.2.5/18); va manzil doimiy emas, chunki barcha manzil sobit belgilar (6.6/9). Nihoyat, markerni ortiqcha yoki minus import bilan ishora qiladi, shuning uchun bu ham emas.


Biroq, 6.6/10, dastur, doimiy ifodalarning boshqa shakllarini qabul qilishi mumkinligini aytadi. Bu asl kodni noto'g'ri shakllangan deb atash kerakmi yoki yo'qmi (noto'g'ri kod diagnostika talab qiladimi) degan ishonchim yo'q. Shubhasiz sizning kompilyatoringiz bu erda boshqa doimiy iboralarni qabul qilmoqda.


Keyingi masala shundan iboratki, markerdan tamsayinga chiqish amaliyotda aniqlanadi. Muayyan ko'rsatgichga mos keladigan aniq raqam bo'lmasa, u ham aniqlanmasligi mumkin. (6.3.2.3/6)

Finally, the + 1 on the end makes no difference. unsigned long arithmetic is well-defined on addition and subtraction, so it is OK if and only if (unsigned long)&x is OK.

2
qo'shib qo'ydi

Ushbu kodni muvofiq bajarish bilan qabul qilinishi shart emas. Sizning savolingizga tegishli pasportni keltirdingiz:

  1. More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
    • an arithmetic constant expression,
    • a null pointer constant,
    • an address constant, or
    • an address constant for an object type plus or minus an integer constant expression.

(unsigned long)&x is none of those things. It's not an arithmetic constant because of C11 6.6/8:

Aritmetik sobit ifodada konveyer operatorlari faqatgina konvertatsiya qilishlari kerak   arifmetik turlarini arifmetik turlarga ajratish.

(markerlarning arifmetik turlari emas, 6.2.5/18); va manzil doimiy emas, chunki barcha manzil sobit belgilar (6.6/9). Nihoyat, markerni ortiqcha yoki minus import bilan ishora qiladi, shuning uchun bu ham emas.


Biroq, 6.6/10, dastur, doimiy ifodalarning boshqa shakllarini qabul qilishi mumkinligini aytadi. Bu asl kodni noto'g'ri shakllangan deb atash kerakmi yoki yo'qmi (noto'g'ri kod diagnostika talab qiladimi) degan ishonchim yo'q. Shubhasiz sizning kompilyatoringiz bu erda boshqa doimiy iboralarni qabul qilmoqda.


Keyingi masala shundan iboratki, markerdan tamsayinga chiqish amaliyotda aniqlanadi. Muayyan ko'rsatgichga mos keladigan aniq raqam bo'lmasa, u ham aniqlanmasligi mumkin. (6.3.2.3/6)

Finally, the + 1 on the end makes no difference. unsigned long arithmetic is well-defined on addition and subtraction, so it is OK if and only if (unsigned long)&x is OK.

2
qo'shib qo'ydi

Avvalo, sizning boshlang'ichingiz mutlaqo doimiy ifoda emas. Agar a mahalliy hajmiga ega bo'lsa, unda suyakka surilgan bo'lsa, u ish vaqti davomida manzilni tayinlaydi. C11 6.6/7, ko'rsatgichning doimiy ifodasi bo'lishi uchun 6,6/9 da quyidagicha aniqlangan manzil doimiyligi bo'lishi kerak:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type.

(Ibratli minalar)


Sizning kodingiz standart C bo'ladimi-yo'qmi, ha ha. Nuqta ko'rsatilgan xatti-harakatlarning turli shakllari bilan birga kelishi mumkin bo'lsa-da, tamsayılar uchun pointer konvertatsiya qilishga ruxsat beriladi. 6.5/6-da ko'rsatilgan:

Har qanday ko'rsatgich turi bir tamsayı turiga aylantirilishi mumkin. Bundan tashqari   oldindan aniqlangan bo'lsa, natija amalga oshiriladi. Agar   natija tamsayt turida ifodalanishi mumkin emas, xatti-harakati   aniqlanmagan. Natijada har qanday qiymat oralig'ida bo'lishi kerak emas   tamsayı turi.

Pointer butun songa mos kelishi uchun ishonch hosil qilish uchun uintptr_t dan foydalaning. Lekin, siz bu savolni joylashtirganingiz sababli konvertatsiyani tamsaytirmoqchi emas deb o'ylamayman.


Agar tamsayılarning to'kilmasligi uni kompilyatsiya vaqtining doimiy bo'lishiga to'sqinlik qiladigan bo'lsa, men bu fikrni qaerdan olganingizni bilmayman. Fikringizni to'g'ri deb bilmayman, masalan, (INT_MAX + INT_MAX) - kompilyatsiya vaqtining doimiyligi va u ortiqcha to'ldirish kafolatidir. (GCC Sizga ogohlantirish beradi.) Agar u to'kib tashlansa, u aniqlanmagan xatti-harakatni keltirib chiqaradi.


Nima uchun derleme vaqtida doimiy bo'lmasin, bu ifoda haqida xatolarga duch kelasizmi, bilmayman. 4.9.1 gcc-da uni ko'chira olmayman. Har ikkala statik va avtomatik saqlash muddati bilan a ni e'lon qilishni harakat qildim, ammo farq yo'q.

Qanday tasodifan C90 deb yoziladi, shuning uchun gcc sizga "xato: dastlabki element elementi hisoblanmaydi" deb aytiladi. Yoki gcc mening versiyamda tuzilgan kompilyator xatolari bo'lishi mumkin.

1
qo'shib qo'ydi
INT_MAX + INT_MAX - doimiy ifoda emas. Qarang: 6.6/4 "Har bir sobit iborani turi uchun vakolatli qiymat oralig'ida joylashgan sog'lomlik qiymatini baholash kerak." Men ham ushbu atamani atayin, doimiy so'zlar UB ni har qanday shaklda o'z ichiga olishi mumkin emasligini anglatadi.
qo'shib qo'ydi muallif M.M, manba
@Lundin UB ish vaqti xususiyati. Kompilyator, dasturni ishga tushirilganda UBga olib kelishi kafolatlangan bo'lsa, dasturni tarjima qilishdan voz kechishi mumkin; (masalan, void foo() {int x [] = {INT_MAX + INT_MAX};} va dasturga zarurat yo'q foo() ). Hech qanday diagnostika ishlab chiqarilmasa, u derleyici xatosi, chunki bu cheklovlar qismida.
qo'shib qo'ydi muallif M.M, manba
@Lundin Ushbu kodni veb-saytga joylashtirdim: int a; unsigned uzun b [] = {(unsigned int) va a + 1}; , kompilyatsiya urish va har ikkala ogohlantirish va xato ham bo'ldi: ogohlantirishi: ko'rsatgichdan turli o'lchamdagi tovushga chiqariladi [-Wpointer- int-cast] va xato: initializer elementi doimiy emas. .
qo'shib qo'ydi muallif anol, manba
gcc, faqat birinchi holatda emas, balki ikkinchi holatda (agar int o'rniga uzun o'rniga uzatilsa). Men gccni faqat magistraldan (5.0.0) tuzgan edim va u ikkinchi versiyani rad etadi. GCC 4.9.2 dan foydalanishni da'vo qiladigan Ushbu onlayn C99 derleyici , ayni xatoni ishlab chiqaradi.
qo'shib qo'ydi muallif anol, manba
@anol Ushbu kod "ko'rsatgichdan butun songacha ..." ogohlantirishini beradi, lekin boshlang'ich haqida hech narsa sobit emas.
qo'shib qo'ydi muallif Lundin, manba
Yo'q, bu ogohlantirish ham bermaydi. Sizga yuborgan kod siz foydalanadigan kod emas degan xulosani beradi.
qo'shib qo'ydi muallif Lundin, manba
@MattMcNabb To'liq to'lib toshgan holda, men derazachi oldin biror narsa nimani anglatadimi yoki yo'qmi degan qarorga kelishidan oldin UB ni olishni o'ylayman. Ikki tomonlama ikkilik birikma ikkita qo'shimcha raqami sifatida ifodalanishi mumkin, chunki amaliyotda kompilyator, ehtimol, ortiqcha UB bilan duch kelganida bir noxush raqamni keltirib chiqaradi va keyin uni doimiy ifoda sifatida ishlatadi. O'ylaymanki, u erda bironta kompilyatorda buni ko'rasiz. Masalan, INT_MAX + INT_MAX doimiy ifodasi uchun GCC Sizga 2 va 4 bayt hajmini beradi.
qo'shib qo'ydi muallif Lundin, manba
Kodda yuqorida uchta izoh va gcc 4.9.1-16ubuntu6 (ya'ni, hozirgi vaqtda Ubuntu 14.10 dan biri) yozilsa, men 64 ta xabarni tuzishda ogohlantirish va xatolik (@anol kabi) -bit rejimida va 32-bitli rejimda ( gcc -m32 file.c ) hech narsa yo'q (@ lundin).
qo'shib qo'ydi muallif Virgile, manba

Avvalo, sizning boshlang'ichingiz mutlaqo doimiy ifoda emas. Agar a mahalliy hajmiga ega bo'lsa, unda suyakka surilgan bo'lsa, u ish vaqti davomida manzilni tayinlaydi. C11 6.6/7, ko'rsatgichning doimiy ifodasi bo'lishi uchun 6,6/9 da quyidagicha aniqlangan manzil doimiyligi bo'lishi kerak:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type.

(Ibratli minalar)


Sizning kodingiz standart C bo'ladimi-yo'qmi, ha ha. Nuqta ko'rsatilgan xatti-harakatlarning turli shakllari bilan birga kelishi mumkin bo'lsa-da, tamsayılar uchun pointer konvertatsiya qilishga ruxsat beriladi. 6.5/6-da ko'rsatilgan:

Har qanday ko'rsatgich turi bir tamsayı turiga aylantirilishi mumkin. Bundan tashqari   oldindan aniqlangan bo'lsa, natija amalga oshiriladi. Agar   natija tamsayt turida ifodalanishi mumkin emas, xatti-harakati   aniqlanmagan. Natijada har qanday qiymat oralig'ida bo'lishi kerak emas   tamsayı turi.

Pointer butun songa mos kelishi uchun ishonch hosil qilish uchun uintptr_t dan foydalaning. Lekin, siz bu savolni joylashtirganingiz sababli konvertatsiyani tamsaytirmoqchi emas deb o'ylamayman.


Agar tamsayılarning to'kilmasligi uni kompilyatsiya vaqtining doimiy bo'lishiga to'sqinlik qiladigan bo'lsa, men bu fikrni qaerdan olganingizni bilmayman. Fikringizni to'g'ri deb bilmayman, masalan, (INT_MAX + INT_MAX) - kompilyatsiya vaqtining doimiyligi va u ortiqcha to'ldirish kafolatidir. (GCC Sizga ogohlantirish beradi.) Agar u to'kib tashlansa, u aniqlanmagan xatti-harakatni keltirib chiqaradi.


Nima uchun derleme vaqtida doimiy bo'lmasin, bu ifoda haqida xatolarga duch kelasizmi, bilmayman. 4.9.1 gcc-da uni ko'chira olmayman. Har ikkala statik va avtomatik saqlash muddati bilan a ni e'lon qilishni harakat qildim, ammo farq yo'q.

Qanday tasodifan C90 deb yoziladi, shuning uchun gcc sizga "xato: dastlabki element elementi hisoblanmaydi" deb aytiladi. Yoki gcc mening versiyamda tuzilgan kompilyator xatolari bo'lishi mumkin.

1
qo'shib qo'ydi
@Lundin UB ish vaqti xususiyati. Kompilyator, dasturni ishga tushirilganda UBga olib kelishi kafolatlangan bo'lsa, dasturni tarjima qilishdan voz kechishi mumkin; (masalan, void foo() {int x [] = {INT_MAX + INT_MAX};} va dasturga zarurat yo'q foo() ). Hech qanday diagnostika ishlab chiqarilmasa, u derleyici xatosi, chunki bu cheklovlar qismida.
qo'shib qo'ydi muallif M.M, manba
INT_MAX + INT_MAX - doimiy ifoda emas. Qarang: 6.6/4 "Har bir sobit iborani turi uchun vakolatli qiymat oralig'ida joylashgan sog'lomlik qiymatini baholash kerak." Men ham ushbu atamani atayin, doimiy so'zlar UB ni har qanday shaklda o'z ichiga olishi mumkin emasligini anglatadi.
qo'shib qo'ydi muallif M.M, manba
gcc, faqat birinchi holatda emas, balki ikkinchi holatda (agar int o'rniga uzun o'rniga uzatilsa). Men gccni faqat magistraldan (5.0.0) tuzgan edim va u ikkinchi versiyani rad etadi. GCC 4.9.2 dan foydalanishni da'vo qiladigan Ushbu onlayn C99 derleyici , ayni xatoni ishlab chiqaradi.
qo'shib qo'ydi muallif anol, manba
@Lundin Ushbu kodni veb-saytga joylashtirdim: int a; unsigned uzun b [] = {(unsigned int) va a + 1}; , kompilyatsiya urish va har ikkala ogohlantirish va xato ham bo'ldi: ogohlantirishi: ko'rsatgichdan turli o'lchamdagi tovushga chiqariladi [-Wpointer- int-cast] va xato: initializer elementi doimiy emas. .
qo'shib qo'ydi muallif anol, manba
@anol Ushbu kod "ko'rsatgichdan butun songacha ..." ogohlantirishini beradi, lekin boshlang'ich haqida hech narsa sobit emas.
qo'shib qo'ydi muallif Lundin, manba
Yo'q, bu ogohlantirish ham bermaydi. Sizga yuborgan kod siz foydalanadigan kod emas degan xulosani beradi.
qo'shib qo'ydi muallif Lundin, manba
@MattMcNabb To'liq to'lib toshgan holda, men derazachi oldin biror narsa nimani anglatadimi yoki yo'qmi degan qarorga kelishidan oldin UB ni olishni o'ylayman. Ikki tomonlama ikkilik birikma ikkita qo'shimcha raqami sifatida ifodalanishi mumkin, chunki amaliyotda kompilyator, ehtimol, ortiqcha UB bilan duch kelganida bir noxush raqamni keltirib chiqaradi va keyin uni doimiy ifoda sifatida ishlatadi. O'ylaymanki, u erda bironta kompilyatorda buni ko'rasiz. Masalan, INT_MAX + INT_MAX doimiy ifodasi uchun GCC Sizga 2 va 4 bayt hajmini beradi.
qo'shib qo'ydi muallif Lundin, manba
Kodda yuqorida uchta izoh va gcc 4.9.1-16ubuntu6 (ya'ni, hozirgi vaqtda Ubuntu 14.10 dan biri) yozilsa, men 64 ta xabarni tuzishda ogohlantirish va xatolik (@anol kabi) -bit rejimida va 32-bitli rejimda ( gcc -m32 file.c ) hech narsa yo'q (@ lundin).
qo'shib qo'ydi muallif Virgile, manba

Avvalo, sizning boshlang'ichingiz mutlaqo doimiy ifoda emas. Agar a mahalliy hajmiga ega bo'lsa, unda suyakka surilgan bo'lsa, u ish vaqti davomida manzilni tayinlaydi. C11 6.6/7, ko'rsatgichning doimiy ifodasi bo'lishi uchun 6,6/9 da quyidagicha aniqlangan manzil doimiyligi bo'lishi kerak:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type.

(Ibratli minalar)


Sizning kodingiz standart C bo'ladimi-yo'qmi, ha ha. Nuqta ko'rsatilgan xatti-harakatlarning turli shakllari bilan birga kelishi mumkin bo'lsa-da, tamsayılar uchun pointer konvertatsiya qilishga ruxsat beriladi. 6.5/6-da ko'rsatilgan:

Har qanday ko'rsatgich turi bir tamsayı turiga aylantirilishi mumkin. Bundan tashqari   oldindan aniqlangan bo'lsa, natija amalga oshiriladi. Agar   natija tamsayt turida ifodalanishi mumkin emas, xatti-harakati   aniqlanmagan. Natijada har qanday qiymat oralig'ida bo'lishi kerak emas   tamsayı turi.

Pointer butun songa mos kelishi uchun ishonch hosil qilish uchun uintptr_t dan foydalaning. Lekin, siz bu savolni joylashtirganingiz sababli konvertatsiyani tamsaytirmoqchi emas deb o'ylamayman.


Agar tamsayılarning to'kilmasligi uni kompilyatsiya vaqtining doimiy bo'lishiga to'sqinlik qiladigan bo'lsa, men bu fikrni qaerdan olganingizni bilmayman. Fikringizni to'g'ri deb bilmayman, masalan, (INT_MAX + INT_MAX) - kompilyatsiya vaqtining doimiyligi va u ortiqcha to'ldirish kafolatidir. (GCC Sizga ogohlantirish beradi.) Agar u to'kib tashlansa, u aniqlanmagan xatti-harakatni keltirib chiqaradi.


Nima uchun derleme vaqtida doimiy bo'lmasin, bu ifoda haqida xatolarga duch kelasizmi, bilmayman. 4.9.1 gcc-da uni ko'chira olmayman. Har ikkala statik va avtomatik saqlash muddati bilan a ni e'lon qilishni harakat qildim, ammo farq yo'q.

Qanday tasodifan C90 deb yoziladi, shuning uchun gcc sizga "xato: dastlabki element elementi hisoblanmaydi" deb aytiladi. Yoki gcc mening versiyamda tuzilgan kompilyator xatolari bo'lishi mumkin.

1
qo'shib qo'ydi
INT_MAX + INT_MAX - doimiy ifoda emas. Qarang: 6.6/4 "Har bir sobit iborani turi uchun vakolatli qiymat oralig'ida joylashgan sog'lomlik qiymatini baholash kerak." Men ham ushbu atamani atayin, doimiy so'zlar UB ni har qanday shaklda o'z ichiga olishi mumkin emasligini anglatadi.
qo'shib qo'ydi muallif M.M, manba
@Lundin UB ish vaqti xususiyati. Kompilyator, dasturni ishga tushirilganda UBga olib kelishi kafolatlangan bo'lsa, dasturni tarjima qilishdan voz kechishi mumkin; (masalan, void foo() {int x [] = {INT_MAX + INT_MAX};} va dasturga zarurat yo'q foo() ). Hech qanday diagnostika ishlab chiqarilmasa, u derleyici xatosi, chunki bu cheklovlar qismida.
qo'shib qo'ydi muallif M.M, manba
@Lundin Ushbu kodni veb-saytga joylashtirdim: int a; unsigned uzun b [] = {(unsigned int) va a + 1}; , kompilyatsiya urish va har ikkala ogohlantirish va xato ham bo'ldi: ogohlantirishi: ko'rsatgichdan turli o'lchamdagi tovushga chiqariladi [-Wpointer- int-cast] va xato: initializer elementi doimiy emas. .
qo'shib qo'ydi muallif anol, manba
gcc, faqat birinchi holatda emas, balki ikkinchi holatda (agar int o'rniga uzun o'rniga uzatilsa). Men gccni faqat magistraldan (5.0.0) tuzgan edim va u ikkinchi versiyani rad etadi. GCC 4.9.2 dan foydalanishni da'vo qiladigan Ushbu onlayn C99 derleyici , ayni xatoni ishlab chiqaradi.
qo'shib qo'ydi muallif anol, manba
Yo'q, bu ogohlantirish ham bermaydi. Sizga yuborgan kod siz foydalanadigan kod emas degan xulosani beradi.
qo'shib qo'ydi muallif Lundin, manba
@MattMcNabb To'liq to'lib toshgan holda, men derazachi oldin biror narsa nimani anglatadimi yoki yo'qmi degan qarorga kelishidan oldin UB ni olishni o'ylayman. Ikki tomonlama ikkilik birikma ikkita qo'shimcha raqami sifatida ifodalanishi mumkin, chunki amaliyotda kompilyator, ehtimol, ortiqcha UB bilan duch kelganida bir noxush raqamni keltirib chiqaradi va keyin uni doimiy ifoda sifatida ishlatadi. O'ylaymanki, u erda bironta kompilyatorda buni ko'rasiz. Masalan, INT_MAX + INT_MAX doimiy ifodasi uchun GCC Sizga 2 va 4 bayt hajmini beradi.
qo'shib qo'ydi muallif Lundin, manba
@anol Ushbu kod "ko'rsatgichdan butun songacha ..." ogohlantirishini beradi, lekin boshlang'ich haqida hech narsa sobit emas.
qo'shib qo'ydi muallif Lundin, manba
Kodda yuqorida uchta izoh va gcc 4.9.1-16ubuntu6 (ya'ni, hozirgi vaqtda Ubuntu 14.10 dan biri) yozilsa, men 64 ta xabarni tuzishda ogohlantirish va xatolik (@anol kabi) -bit rejimida va 32-bitli rejimda ( gcc -m32 file.c ) hech narsa yo'q (@ lundin).
qo'shib qo'ydi muallif Virgile, manba