"Sizeof (arr [0])" noma'lum harakatlarga olib kelishi mumkinmi?

Chiziqning uzunligini aniqlab olishning yaxshi ma'lum shakli bor:

int arr[10]; 
size_t len = sizeof(arr)/sizeof(arr[0]); 
assert(len == 10); 

Ushbu naqsh doimiy kattalikdagi statik arrays va avtomatik arralar uchun qo'llaniladi. C99 da o'zgaruvchan uzunlikdagi qatorlarga ham qo'llaniladi.

Baytdagi dinamik qator hajmini aniqlash uchun shu kabi g'oyani qo'llashni xohlayman:

size_t known_len = 10; 
int *ptr = malloc(known_len * sizeof(int)); 
size_t size = known_len * sizeof(ptr[0]); 
assert(size == known_len * sizeof(int)); 

sizeof (ptr [0]) ) haqiqiy katalog elementi turini bildirmaydi, chunki known_len * sizeof (int) dan ko'ra yaxshiroqdir. Shuning uchun u turini bilish uchun kodni o'quvchi talab qilmaydi.

Biroq, sizeof (ptr [0]) ifodasi aniqlanmagan xatti-harakatga olib kelishi mumkinmi, men uchun noaniq. Kengaytirilganda:

sizeof(ptr[0]) -> sizeof(*((ptr) + (0))) -> sizeof(*ptr) 

ptr esa 0 bo'lsa, natija ifodasi shubhali:

sizeof(*((int*) 0)) 

C99 standartiga muvofiq:

(C99, 6.3.2.3p3): " 0 qiymatiga ega tamsayıli doimiy ifoda,   yoki void * ni kiritish uchun bunday ifodani yozadigan bo'lsa, null ko'rsatgich deb ataladi   "Null pointerni ajratib olish - aniqlanmagan xatti-harakatlar.

     

(C99, 6.5.3.2.p4) "Agar noto'g'ri qiymat tayinlangan bo'lsa    * operatorining harakati aniqlanmagan.87) "

     

87): "Bu ko'rsatgich orqali ko'rsatgichni o'chirish uchun bekor qiymatlar orasida   unary * operatori null pointer, noma'lum manzildir   ishora qilingan ob'ekt turi uchun hizalanır va bir   ob'ekt o'z umrining oxirigacha ".

Ammo bunday ifodalarning kattaligi aniqlanmagan xatti-harakatga olib kelishi mumkinligini hech qachon aniqlanmagan. Aslida bunday o'lcham kompilyatsiya vaqtida baholanishi kerak.

Mening savollarim:

  • ptr kodi ma'lum bo'lsa va ptr qiymati bo'lsa kodda sizeof (ptr [0]) ma'lum emasmi?
  • Bunday foydalanish C99 standarti bo'yicha oqlanishi mumkinmi? GNU GCC spec?
16
Bir tomondan, malloc (known_len * sizeof (int)) o'rniga malloc (known_len * sizeof * ptr) ni ko'rib chiqing. Agar ptr turini o'zgartirsangiz yoki yashirilmasa (ba'zi .h faylida chuqurroq dafn etilgan bo'lsa), bu uslub odatda to'g'ri va himoya qilishni osonlashtiradi.
qo'shib qo'ydi muallif chux, manba
Bir tomondan, malloc (known_len * sizeof (int)) o'rniga malloc (known_len * sizeof * ptr) ni ko'rib chiqing. Agar ptr turini o'zgartirsangiz yoki yashirilmasa (ba'zi .h faylida chuqurroq dafn etilgan bo'lsa), bu uslub odatda to'g'ri va himoya qilishni osonlashtiradi.
qo'shib qo'ydi muallif chux, manba
Aloqador savolga qo'shimcha javob qo'shdim. Bu erda tashvishlanish arr ko'rsatkichi e'lon qilingan holatlar haqida, masalan, int n = 10; int (* arr) [n] = NULL; , ya'ni VLA uchun ko'rsatgich. C tilida sizeof argumenti VLA turi (!) Bo'lsa, ish vaqti davomida baholanadi. Bu holatda savol sizeof arr [0] ning aniqlanmagan xatti-harakatni keltirib chiqarishi kerakmi? Ehtimol, bu.
qo'shib qo'ydi muallif AnT, manba
Aloqador savolga qo'shimcha javob qo'shdim. Bu erda tashvishlanish arr ko'rsatkichi e'lon qilingan holatlar haqida, masalan, int n = 10; int (* arr) [n] = NULL; , ya'ni VLA uchun ko'rsatgich. C tilida sizeof argumenti VLA turi (!) Bo'lsa, ish vaqti davomida baholanadi. Bu holatda savol sizeof arr [0] ning aniqlanmagan xatti-harakatni keltirib chiqarishi kerakmi? Ehtimol, bu.
qo'shib qo'ydi muallif AnT, manba
Aslida, boglangan savol VLA bo'lmagan kontekstlar bilan chegaralanadi, ammo bu savol darhol bunday cheklovga ega emas. Bu uni nusxa ko'chirishni taqiqlaydi.
qo'shib qo'ydi muallif AnT, manba
Aslida, boglangan savol VLA bo'lmagan kontekstlar bilan chegaralanadi, ammo bu savol darhol bunday cheklovga ega emas. Bu uni nusxa ko'chirishni taqiqlaydi.
qo'shib qo'ydi muallif AnT, manba

7 javoblar

ptr [0] ifodasi sizeof (ptr [0]) da baholanmaydi. Hajmi kompilyatsiya vaqtida ptr [0] dan foydalangan holda aniqlanadi.

C11: 6.5.3.4:

sizeof operatori operandning o'lchamini (baytda), ya'ni ifodani yoki turdagi parentezli nomi bo'lishi mumkin. hajmi operandning turidan aniqlanadi . Natija butun sondir. Agar operandning turi o'zgaruvchan uzunlik qatori bo'lsa, operand baholanadi; Aks holda, operand baholanmaydi va natija aninteger sobit bo'ladi.

Ya'ni, aniqlanmagan harakatlar yo'q.

17
qo'shib qo'ydi

ptr [0] ifodasi sizeof (ptr [0]) da baholanmaydi. Hajmi kompilyatsiya vaqtida ptr [0] dan foydalangan holda aniqlanadi.

C11: 6.5.3.4:

sizeof operatori operandning o'lchamini (baytda), ya'ni ifodani yoki turdagi parentezli nomi bo'lishi mumkin. hajmi operandning turidan aniqlanadi . Natija butun sondir. Agar operandning turi o'zgaruvchan uzunlik qatori bo'lsa, operand baholanadi; Aks holda, operand baholanmaydi va natija aninteger sobit bo'ladi.

Ya'ni, aniqlanmagan harakatlar yo'q.

17
qo'shib qo'ydi

Bu aniqlanmagan xatti-harakatga olib kelmaydi.

Argumentlar uzunligi qatorlari hajmini hisobga olmaganda, sizeof - derleme vaqtidagi doimiy ifodadir. Derleyici kompilyatsiya vaqtida ifodani baholash uchun kod ishlab chiqmasdan, uning turini aniqlash uchun ifoda qiladi. Shuning uchun, ptr [0] da (qiymatsiz ko'rsatgich ko'rsatgich) qiymat hech qanday ahamiyatga ega emas.

Bundan tashqari, agar siz o'nta sonni ajratishni istasangiz, quyidagi kabi malloc deb nom berishingiz kerak:

int *ptr = malloc(known_len * sizeof(ptr[0])); 

Aks holda, o'nta baytni ajratasiz, bu esa o'nta sonni saqlash uchun juda kichikdir. Yuqorida ko'rsatilgan ptr iborasi sizeof uchun juda yaxshi bo'lgan chaqiruv paytida uninitialized.

11
qo'shib qo'ydi
@MM: Bu misolda f() ning qaytib qiymati turi int [n] [f ()] . Bundan juda qiziq bir vaziyat, sizeof (* (char [f ()])) kabi bir narsa bo'lishi mumkin, chunki bir tamsayılar uchun bir ko'rsatkichni kattaligi qator uzunligidan mustaqil bo'lishi kerak; Biroq, f() bu holatda baholanadi.
qo'shib qo'ydi muallif supercat, manba
@ M.M: Nol o'lchamdagi turlarni taqiqlash - IMHO-ning qarshi samaradorligi. Agar nol o'lchamli massivni tuzuvchi ofitser bo'lmasa, u manzil haqida faqat bitta narsa haqida gapirish yaxshiroq bo'lar edi. Ulardan hech qanday natija bermaslik, nolga teng bo'lmagan qiymatni qo'shmaslik yoki olib tashlash mumkin emas va ko'rsatgich boshqa biron biriga (shu jumladan, null) teng keladigan tarzda taqqoslanishi mumkin, lekin agar kod ko'rsatgich bilan mavjud bo'lgan har qanday taqiqlangan amallarni bajarmasa, Har qanday UBga sabab bo'lishi mumkin.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Sizning namunangizda semantik sabablar yo'q, derleyici, i ++ ni baholashi kerak; sizeof ifodasi sobit bo'lmasa ham, sintaksisi so'zining ifodasi i ++ ifodasi ahamiyatsiz bo'ladi. sizeof ichidagi bir ifoda qiymatini tegishli deb bilish uchun, sizeof (int [i ++) bilan ifodada bir turdagi yaratish ]) va bunday xatti-harakatlar foydali bo'ladigan har qanday holatlar haqida o'ylay olmayman.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Men yozganidek, ushbu operatsiyani amalga oshirish natijalariga ko'ra, syntactically no if i degan iboralarni baholashni talab qiladigan darajada hayratlanarli holat. VLA'lar uchun yagona qonuniy foydalanish, o'zgarmaydigan uzunlikdagi arraylarni o'z ichiga olgan o'zgaruvchining deklaratsiyasida bo'lsa, hatto doimiy qiymat bermaydigan sizeof da (masalan sizning misolingizda) uning dalillarini vaqt bo'yicha baholash. Faqatgina juda g'alati holatlarda sizeof da hisoblash natijasi uning qiymatiga ta'sir qiladi va bunday narsalarni bekor qilish tilning ifodasini zaiflashtirishi mumkin deb o'ylamayman.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Mening fikrim shuki, o'lchamdagi argumentga funktsiya chaqiruvi yoki ko'rsatgichsiz ishora kabi narsalar kiritilgan bo'lsa ham, men bajariladigan vazifani bajarish uchun hech qanday asos yo'q, yoki VLA holatlarida ko'rsatgichni yo'q qilish uchun ishora qilaman. foo ni baholashni talab qilishi mumkin bo'lgan sizeof intoflu [foo ()] deyilgan bo'lsa, lekin bunday tuzilishga biron bir foydali narsa ko'rmayapman.
qo'shib qo'ydi muallif supercat, manba
Qaysi holatlarda sizeof aslida bajarish ni o'z vaqtida bajarish kerak? Agar o'lchamdagi argument VLA ni o'z ichiga olgan bo'lsa ham, sizeof har qanday sababga ko'ra dasturda allaqachon UB bilan shug'ullanganmi?
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Foydali haqiqat: typedef executable ifodasi (=) sifatida ish yuritishi mumkin typedef int arr [i ++]; kodi i faqat uning doirasi uchun tegishli bo'lgan deklaratsiya yarating.
qo'shib qo'ydi muallif supercat, manba
Misolingizdagi @supercat kodi f() so'ralganligini aniqlanmagan. Menimcha, bu savolning asl nusxasi bilan bog'liq bo'lgan bettter spetsifikatsiyasiga ega bo'lishda qandaydir qiymat bo'lishi mumkin (u

p = malloc (n * sizeof * p) dan foydalana olmaysiz degan ma'noni anglatadi); , agar siz ushbu UB uchun hech qanday yomon narsa bo'lmaydi degan xursand bo'lmasangiz

qo'shib qo'ydi muallif M.M, manba
@supercat: int (* ptr) [f ()] = malloc (sizeof (int [n] [f ()])); Kompilyator faqat F() (ikkinchisi) bu erda to'g'ri hajmdagi baytlarni topish kerakligi sababli. Demak, imkoniyatlar quyidagicha ko'rinadi: (a) standart nima deydi, (b) aniqlanmagan xatti-harakatlar, (v) cheklovni buzish. Variant (b) keraksiz ko'rinadi. (C) yaxshi bo'lar edi, lekin, ehtimol, ba'zi bir qonunni bekor qilmasdan, shu maqsadni amalga oshiradigan qoidalarni tuzish ham oson emas.
qo'shib qo'ydi muallif M.M, manba
@supercat typedef menga sizeof ning an'anaviy ma'noda baholanadigan, yonma-yon effektlar bilan to'la bir misol uchun fikr berdi! Bu erda . Qizig'i shundaki, i ikkinchi o'lcham qo'shilmagunimcha, o'sish bo'lmaydi.
qo'shib qo'ydi muallif dasblinkenlight, manba
Rahmat. Men o'rnak ko'rsatdim.
qo'shib qo'ydi muallif mrsmith, manba

Bu aniqlanmagan xatti-harakatga olib kelmaydi.

Argumentlar uzunligi qatorlari hajmini hisobga olmaganda, sizeof - derleme vaqtidagi doimiy ifodadir. Derleyici kompilyatsiya vaqtida ifodani baholash uchun kod ishlab chiqmasdan, uning turini aniqlash uchun ifoda qiladi. Shuning uchun, ptr [0] da (qiymatsiz ko'rsatgich ko'rsatgich) qiymat hech qanday ahamiyatga ega emas.

Bundan tashqari, agar siz o'nta sonni ajratishni istasangiz, quyidagi kabi malloc deb nom berishingiz kerak:

int *ptr = malloc(known_len * sizeof(ptr[0])); 

Aks holda, o'nta baytni ajratasiz, bu esa o'nta sonni saqlash uchun juda kichikdir. Yuqorida ko'rsatilgan ptr iborasi sizeof uchun juda yaxshi bo'lgan chaqiruv paytida uninitialized.

11
qo'shib qo'ydi
@ M.M: Nol o'lchamdagi turlarni taqiqlash - IMHO-ning qarshi samaradorligi. Agar nol o'lchamli massivni tuzuvchi ofitser bo'lmasa, u manzil haqida faqat bitta narsa haqida gapirish yaxshiroq bo'lar edi. Ulardan hech qanday natija bermaslik, nolga teng bo'lmagan qiymatni qo'shmaslik yoki olib tashlash mumkin emas va ko'rsatgich boshqa biron biriga (shu jumladan, null) teng keladigan tarzda taqqoslanishi mumkin, lekin agar kod ko'rsatgich bilan mavjud bo'lgan har qanday taqiqlangan amallarni bajarmasa, Har qanday UBga sabab bo'lishi mumkin.
qo'shib qo'ydi muallif supercat, manba
@MM: Bu misolda f() ning qaytib qiymati turi int [n] [f ()] . Bundan juda qiziq bir vaziyat, sizeof (* (char [f ()])) kabi bir narsa bo'lishi mumkin, chunki bir tamsayılar uchun bir ko'rsatkichni kattaligi qator uzunligidan mustaqil bo'lishi kerak; Biroq, f() bu holatda baholanadi.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Sizning namunangizda semantik sabablar yo'q, derleyici, i ++ ni baholashi kerak; sizeof ifodasi sobit bo'lmasa ham, sintaksisi so'zining ifodasi i ++ ifodasi ahamiyatsiz bo'ladi. sizeof ichidagi bir ifoda qiymatini tegishli deb bilish uchun, sizeof (int [i ++) bilan ifodada bir turdagi yaratish ]) va bunday xatti-harakatlar foydali bo'ladigan har qanday holatlar haqida o'ylay olmayman.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Men yozganidek, ushbu operatsiyani amalga oshirish natijalariga ko'ra, syntactically no if i degan iboralarni baholashni talab qiladigan darajada hayratlanarli holat. VLA'lar uchun yagona qonuniy foydalanish, o'zgarmaydigan uzunlikdagi arraylarni o'z ichiga olgan o'zgaruvchining deklaratsiyasida bo'lsa, hatto doimiy qiymat bermaydigan sizeof da (masalan sizning misolingizda) uning dalillarini vaqt bo'yicha baholash. Faqatgina juda g'alati holatlarda sizeof da hisoblash natijasi uning qiymatiga ta'sir qiladi va bunday narsalarni bekor qilish tilning ifodasini zaiflashtirishi mumkin deb o'ylamayman.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Foydali haqiqat: typedef executable ifodasi (=) sifatida ish yuritishi mumkin typedef int arr [i ++]; kodi i faqat uning doirasi uchun tegishli bo'lgan deklaratsiya yarating.
qo'shib qo'ydi muallif supercat, manba
@dasblinkenlight: Mening fikrim shuki, o'lchamdagi argumentga funktsiya chaqiruvi yoki ko'rsatgichsiz ishora kabi narsalar kiritilgan bo'lsa ham, men bajariladigan vazifani bajarish uchun hech qanday asos yo'q, yoki VLA holatlarida ko'rsatgichni yo'q qilish uchun ishora qilaman. foo ni baholashni talab qilishi mumkin bo'lgan sizeof intoflu [foo ()] deyilgan bo'lsa, lekin bunday tuzilishga biron bir foydali narsa ko'rmayapman.
qo'shib qo'ydi muallif supercat, manba
Qaysi holatlarda sizeof aslida bajarish ni o'z vaqtida bajarish kerak? Agar o'lchamdagi argument VLA ni o'z ichiga olgan bo'lsa ham, sizeof har qanday sababga ko'ra dasturda allaqachon UB bilan shug'ullanganmi?
qo'shib qo'ydi muallif supercat, manba
Misolingizdagi @supercat kodi f() so'ralganligini aniqlanmagan. Menimcha, bu savolning asl nusxasi bilan bog'liq bo'lgan bettter spetsifikatsiyasiga ega bo'lishda qandaydir qiymat bo'lishi mumkin (u

p = malloc (n * sizeof * p) dan foydalana olmaysiz degan ma'noni anglatadi); , agar siz ushbu UB uchun hech qanday yomon narsa bo'lmaydi degan xursand bo'lmasangiz

qo'shib qo'ydi muallif M.M, manba
@supercat: int (* ptr) [f ()] = malloc (sizeof (int [n] [f ()])); Kompilyator faqat F() (ikkinchisi) bu erda to'g'ri hajmdagi baytlarni topish kerakligi sababli. Demak, imkoniyatlar quyidagicha ko'rinadi: (a) standart nima deydi, (b) aniqlanmagan xatti-harakatlar, (v) cheklovni buzish. Variant (b) keraksiz ko'rinadi. (C) yaxshi bo'lar edi, lekin, ehtimol, ba'zi bir qonunni bekor qilmasdan, shu maqsadni amalga oshiradigan qoidalarni tuzish ham oson emas.
qo'shib qo'ydi muallif M.M, manba
@supercat typedef menga sizeof ning an'anaviy ma'noda baholanadigan, yonma-yon effektlar bilan to'la bir misol uchun fikr berdi! Bu erda . Qizig'i shundaki, i ikkinchi o'lcham qo'shilmagunimcha, o'sish bo'lmaydi.
qo'shib qo'ydi muallif dasblinkenlight, manba
Rahmat. Men o'rnak ko'rsatdim.
qo'shib qo'ydi muallif mrsmith, manba

Umuman olganda, agar biror narsa etishmayotgan bo'lsam, sizeof ostida bo'sh ko'rsatkichni ajratib olish aniqlanmagan xatti-harakatga olib kelishi mumkin. C99dan boshlab, sizeof faqat kompilyatsiya vaqt tarkibi emas. sizeof operandi operanda turi VLA bo'lsa, ish vaqti davomida baholanadi.

Keling, quyidagi misolni ko'rib chiqaylik

unsigned n = 10;
int (*a)[n] = NULL;//`a` is a pointer to a VLA 

unsigned i = 0;
sizeof a[i++];     //applying `sizeof` to a VLA

C99 standarti bo'yicha sizeof argumenti baholanishi kerak edi (ya'ni, i sonini oshirish kerak). Shunga qaramasdan, a [0] dagi null nuqta nuqsoni bu erda aniqlanmagan xatti-harakatlar ishlab chiqarishiga ishonchim komil emas.

2
qo'shib qo'ydi
Standartlar juda ko'p hollarda standartlarni nolga teng narxlarda aniqlashi mumkin bo'lgan holatlar mavjud. Bularning barchasi, derleyiciler endi ularni kodni yo'q qilish uchun uzrli sabab sifatida foydalana olmasliklari va UBdan qochishning kodi bu boshqa maqsadga xizmat qilmaydi va optimallashni olib tashlay olmaydi.
qo'shib qo'ydi muallif supercat, manba
@mrsmith: alloca() ni taniyman; hech qanday "erkinlik" talab qilmaydigan va joylashtirolmaydigan ko'pgina dasturlarda qiyinchiliklarga olib keladi va muayyan pastadir kontekstida uning foydasini cheklaydi. Har qanday holatda, typedef ega bo'lishni istisno qiladigan so'zlarni bajarish g'aroyib ko'rinadi. Gcc-dagi ushbu naqshni moslashtirish uchun qanchalik o'zgarish kerakligi qiziq.
qo'shib qo'ydi muallif supercat, manba
faqatgina #define stalloc (x) malloc (x) # stefree (x) bepul (x) to'g'ri stalloc/stfree ekspluatatsiya qilingan kod bilan tezlikni oshirish. Amalga oshirilishi mumkin bo'lgan typedef kodini yaratish, menga ochiqchasiga g'alati tuyuladi.
qo'shib qo'ydi muallif supercat, manba
@mrsmith: Nima sodir bo'layotganini tushunish uchun if (z) typedef int arr [i ++]; ta'sirini hisobga olish foydali bo'lishi mumkin. Oddiy qilib aytganda typedef bir executable iborasi bo'lishi kerakligini o'ylamaydi, lekin VLAsni standartlarga qo'shgan insonlar, ehtimol, bu bo'lishi kerak deb o'ylashadi. Ochig'ini aytsam, VLA-larni tark etish va "malloc" kabi o'zini tutishi kerak bo'lgan "stallok" ga ega bo'lish yaxshiroq bo'lar edi, ammo "stalloc" qo'ng'iroqlari LIFO tartibida "stfree" chaqiruvlari bilan mos kelishini talab qiladi, malloc/free bilan mos keladigan harakatlar; har qanday kompilyator stalloc/stfree dasturlarni ta'minlab berishi kerak ...
qo'shib qo'ydi muallif supercat, manba
Mening fikrimcha, bu standart, albatta, int (* p) [n] = NULL; p = malloc (sizeof p [0]); - bu aniqlanmagan xatti-harakatlardir, ammo men standartni ushbu sohada nuqsonli deb hisoblash kerak deb o'ylayman. Qo'mita ehtimol ehtiyotkorlik tarafida xatolikka yo'l qo'ydi (yoki "bu ahamiyatsiz tafsilotlarni aniqlash uchun kamroq vaqt sarflash" tomoni) va o'lchamdagi barcha VLA argumentlarini baholash mumkin; bu ishni baholash kerak emas, deb aytadigan qoida bo'yicha fikrlarni shakllantirish va olish uchun vaqt ajratishdan farq qiladi (ammo boshqa holatlar aniq baholanadi).
qo'shib qo'ydi muallif M.M, manba
Standartga javob bermaslik, agar natijaning o'lchamiga ta'sir qilmasa, subkaftsiyani baholash mumkin yoki baholamasligi mumkin
qo'shib qo'ydi muallif M.M, manba
GCC 4.8.3 da sinab ko'rsak, mening namunamda i to'g'ri ravishda oshib boradi.
qo'shib qo'ydi muallif AnT, manba
@mrsmith :: Sizning "juda oddiy" misolingiz ( int b [len] ) bilan bog'liq emas. sizeof misolida int qiymatiga b [i ++] qo'llaniladi. int - VLA emas. Shunday qilib, ifoda qiymatini baholash kerak emas va i qiymatini oshirish kerak emas. sizeof ostida bir "VLA" ni ishlatish kifoya emas, shuning uchun sizeof to'g'ridan to'g'ri VLA turiga . Shuning uchun men misol uchun sizeof misolini ko'rib chiqaylik.
qo'shib qo'ydi muallif AnT, manba
@mrsmith: GCC bu muayyan xatti-harakatni o'z ichiga olgan va oxir-oqibatda bu o'zgarish sodir bo'ldi. Shunga qaramay, GCC'nin qaysi versiyalarida xato borligini va qanday versiyani tuzatganini eslay olmayman. Coliru tomonidan ishlatiladigan GCC versiyasi to'g'ri ishlaydi: coliru.stacked-crooked.com/a/fa3f47394f9fa3a4. i qiymatini oshiradi. Men sizning 4.1.2-da, bu borada hali ham g'ayritabiiy ekanligiga shubha qilaman.
qo'shib qo'ydi muallif AnT, manba
@mrsmith: Birinchi izohingizdagi misollar namoyish etilmaydi, chunki sizeof VLA turini ifodalashda qo'llanilmaydi. Bu kabi sizeof misolini yaratish uchun ataylab tayyorlangan ifodani oladi va int (* a) [n] buni bajarishning bir usuli hisoblanadi.
qo'shib qo'ydi muallif AnT, manba
i aslida ancha oddiy holatda ham ortib bormaydi void baz (int len) {int b [len]; int i = 0; printf ("% zu \ n", sizeof (b [++ i]))); printf ("% d \ n", i); } , 4 va 0 ni bosadi.
qo'shib qo'ydi muallif mrsmith, manba
int (* a) [n] degan ma'noni anglatadi. Lekin, albatta, muammoli. Sizning namunangiz GCC 4.1.2 da "code" -std = c99 va i bilan ishlaydi, lekin men uni standart nuqtai nazardan qanday izohlashni bilmayman.
qo'shib qo'ydi muallif mrsmith, manba
Izohingiz uchun tashakkur!
qo'shib qo'ydi muallif mrsmith, manba
Shunday qilib, agar "int (* a) [n]" aslida VLA tipidagi int [n] uchun ko'rsatgich bo'lsa, uning hajmi ma'lum vaqt kompilyatsiya qilinmaydi. UB uchun joy bo'lishi mumkin.
qo'shib qo'ydi muallif mrsmith, manba
@supercat: Yig'ma xotira ajratish uchun alloca() chaqiriq mavjud. Bundan tashqari, free() chaqirig'iga mos kelishini talab qilmaydi.
qo'shib qo'ydi muallif mrsmith, manba
VLA holatlariga javoblarni hisobga olib, VLA bilan bog'liq muammo yo'q: void foo (int len) {int vla [len]; printf ("% zu \ n", sizeof (vla [0]))); int * p = vla; printf ("% zu \ n", sizeof (p [0]))); } Birinchi holatda vla o'zgarmaydigan uzunlik qatori va dimension (vla) ish vaqti davomida baholanishi bilan birga, o'lcham hajmi (vla [0]) kompilyatsiya vaqtida hisoblab chiqilishi mumkin. Yaxshiyamki, vlani yo'qligi kafolatlanadi. Ikkinchi holda, p (p) ning o'lchamini (p [0]) o'lchamdagi kabi baholamaslik kerak.
qo'shib qo'ydi muallif mrsmith, manba

Kod yomon.

size_t known_len = 10; 
int *ptr = malloc(known_len); 
size_t size = known_len * sizeof(ptr[0]); 
assert(size == known_len * sizeof(int)); 

Ko'rib chiqish nuqtasida xotira ajratish hajmi 10 bayt. Int uchun 10 nuqta emas.

 known_len/sizeof(ptr[0]) 

ajratish mumkin bo'lgan tamsayılar sonini beradi.

Aslida, ajratishning oxirigacha ketmasligingiz va aniqlanmagan xatti-harakatlarga olib keladi.

Malloc (ma'lum_length * dimension ptr [0]) ni ko'rib chiqing;

1
qo'shib qo'ydi
bu savolni endi o'zgartirib yuborganligini tasavvur qiling
qo'shib qo'ydi muallif M.M, manba
Siz haqsiz, maqsad malloc (ma'lum_len * sizeof (int)). Men savolni tuzataman.
qo'shib qo'ydi muallif mrsmith, manba

Bir ifoda sifatida (deklaratsiya emas), ptr [0] kodi * ptr bilan bir xil.

ptr kodi ma'lum bo'lsa va uni bekor qilmagan bo'lsa, sizeof (* ptr) ustida ishlaydigan sizeof Shuningdek, sizeof (ptr [0]) kabi.

1
qo'shib qo'ydi