Ishlash vaqtida C - struct * quyi?

Menda quyidagi kod bor:

struct str1
{
    int common1;
    char common2;
    char *common3;
    long int aaaaaaaa;
}

struct str2
{
    char bbbb;
    char *common3;
    int common1;
    char common2;
}

struct str3
{
    char ccccccccc[200];
    int common1;
    char common2;
    int dddddddd;
    int eeeeeeee;
    char *common3;
}

void somefunc1(struct str1 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

void somefunc2(struct str2 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

void somefunc3(struct str3 var)
{
    printf("%d %c %s", var.common1, var.common2, var.common3);
}

Qanday qilib kodni takrorlashdan qochib, bitta umumiy funktsiyadan foydalanishim mumkinmi? Funktsiya chaqiruvlari ish vaqtida aniqlanishi kerak, shuning uchun so'l o'rinli emas. Funktsiyalar o'rtasidagi barcha farqlar struct a'zolarining emas, balki ularning ismlari.

1
Funksiyalar orasidagi barcha farqlar tuzilmalar ichidagi a'zolar uchun ofsettadir, shuning uchun kod somefunc2() kodi somefunc1() kodidan ancha farq qiladi va somefunc3() da yana ikkala vazifadan farq qiladi. Agar siz uchta ishni bajarish uchun bitta funktsiyani chindan ham bajarishni istasangiz, dan offset so'lini ishlatish kodini yozishingiz kerak va shu bilan birga, ko'rsatilgan koddagi minuscule 'takrorlash' dan ancha katta bo'ladi.
qo'shib qo'ydi muallif Jonathan Leffler, manba
makroslarni chiqarib tashlaganingiz juda yomon. Bu eng yaxshi yechim bu.
qo'shib qo'ydi muallif Jean-François Fabre, manba
qo'shib qo'ydi muallif mentally retarded, manba
@ Jan-FrançoisFabre Men ularni bajarishga qaror qildim, chunki men ularni ish vaqtida qaror qabul qilish uchun foydali emas deb hisoblayman.
qo'shib qo'ydi muallif J. Doe, manba

5 javoblar

«Umumiy» tuzilish a'zolari pozitsiyasi tuzilmalar o'rtasida izchil bo'lmasa, javob yo'q. Buning sababi shundaki, bu struktura o'rtasida haqiqiy umumiylik mavjud emas.

4
qo'shib qo'ydi

Ushbu tuzilish bilan ularning barchasini boshqaradigan yagona funktsiyani yozish qiyin (agar mumkin bo'lmasa). Biroq, ushbu tuzilmani boshqa umumiy tuzilmalardan almashish uchun o'zgartirsangiz, bu mumkin bo'ladi.

struct base
{
    int common1;
    char common2;
    char *common3;
};

struct str1
{
    struct base b;
    long int aaaaaaaa;
};

struct str2
{
    struct base b;
    char bbbb;
};

struct str3
{
    struct base b;
    char ccccccccc[200];
    int dddddddd;
    int eeeeeeee;
};

Eslatma: struct base o'zgaruvchining o'zgaruvchisi struct ning birinchi a'zosi bo'lishi kerak, aks holda bu texnik ishlamaydi.

Endi struct base ga ishora qiluvchi funksiya e'lon qiling.

void somefunc(struct base* var)
{
    printf("%d %c %s\n", var->common1, var->common2, var->common3);
}

Foydalanish:

struct str1 s1 = { 1, 'a', "sfad"};
struct str2 s2 = { 2, 'b', "sdfazx"};
struct str3 s3 = { 3, 'c', "oiurotu"};

somefunc((struct base*) &s1);
somefunc((struct base*) &s2);
somefunc((struct base*) &s3);
3
qo'shib qo'ydi
struct bazasi tipidagi uch bayt - chiqindilarni dastlab, keyin int va keyin char ishlatib, ko'p hollarda qochib ketishi mumkin bo'lgan chiqindilar - umumiy boshlang'ich tartib qoidasidan foydalanish (agar Bir tuzilishning "o'zgarmaydigan" qismi 8 bit yoki 16 bitli har qanday maydonlarni yoki qatorlarni o'z ichiga oladi, ular birinchi bayta keng tarqalgan so'zni "to'ldirish" uchun joylashtirilishi mumkin2.
qo'shib qo'ydi muallif supercat, manba

C89da, ikki yoki undan ortiq tuzilma mos keluvchi turdagi a'zolarga moslashtirilgan tartibda boshlanadi (ular umumiy boshlang'ich tartibda ishlaydi) va ikkalasi bir xil ittifoqning tarkibiy qismi bo'lsa, umumiy boshlang'ich navbatning har qanday qismi tegishli nomlangan a'zolaridan foydalanib tekshirilishi mumkin. MDHni taqsimlashning har qanday turi. Sizning misolingiz mos keluvchi turlardan foydalanmaydi, shuning uchun u shart emas, lekin mos keluvchi turlarni muvofiq tartibda ishlatish kerak bo'lsa, u bo'lar edi. 1990 yillar oralig'ida C89 kompilyatorlari bir xil printsiplarni strukturalarga mos ravishda qo'llashdi (shuning uchun S1 va S2 strukturalari MDHga a'zo bo'lsa, MDHga a'zo bo'lish uchun har qanday turdagi ko'rsatgichlardan foydalanish mumkin). Standart bu kabi muolajani aniq ko'rsatmasa-da, bu qoidalar kasaba uyushmalariga taalluqli barcha holatlarda qoidani qo'llashni ta'minlash uchun eng qulay usul bo'lib, u barcha ko'rsatgichlarda ham ishora qiladi va ko'pchilik (ehtimol, jumladan, mualliflarning standartlari) derleyiciler aniq ravishda talab qilinadigan yoki qilmasligini tabiiy ravishda kutishlarini kutishgan.

C99, agar kod bir tuzilish turi ko'rsatgichidan foydalanmoqchi bo'lsa MDH davlatlaridan birining boshqa a'zosiga kirish imkoniyati, birlashma turining to'liq ta'rifi, derivat turlar orasida potensial takrorlashni bilishi uchun paydo bo'lishi kerak. Afsuski, ushbu qoida aniq va ravshan maqsadga ega bo'lsa-da (dasturchilar MDH qoidalarini qo'llash uchun kompilyatorlar tomonidan kompilyatsiya qilinmagan tuzilmalarga kirishlar boshqa nomga ega bo'lmaydi deb o'ylashlariga ruxsat berishiga ruxsat berishiga qaramay) ba'zi kompilyatorlar yozuvchilari hech qanday struktura turi ko'rsatilmaydi har ikkala turni o'z ichiga olgan to'liq birlashma turi deklaratsiyasi paydo bo'lishi va hatto tuzilmalar aslida bir xil ittifoq ob'ektining a'zolari bo'lgan taqdirda ham, har qanday boshqa narsaga kirish uchun.

Agar Common Initial Sequence qoidasini ishlatmoqchi bo'lsangiz, unda birinchidan (hatto MDHni ekspluatatsiya qilinmasa bayroqni ishlatib bo'lgandagina) kompilyatorlardan foydalanganingizda -fno-strident-aliasing bayrog'ini ishlatish kerak bo'lishi mumkin. derleyici xatolaridan himoya qilishni ta'minlaydi). Tarkibni ishlatadigan kod derleyici uchun ochiq bo'lishi uchun (masalan, mos birlashma turini ko'rish mumkin), ammo kompilyatorlar yozuvchilari bunday narsalarga e'tibor bermasdan, -fno-strict-aliasing Buning bajarilmasligini ta'minlash uchun zarur bo'ladi.

0
qo'shib qo'ydi

Kodni takrorlashdan qochishim va bitta umumiy funktsiyadan foydalanishim mumkinmi?

Yo'q. Bu C ++ shabloniga o'xshashdir, albatta, bu C ning mavjud emasligi va oldingi protsessorni o'z ichiga olmaguncha, siz uchun analog mavjud emas. C11-da _Generic mavjud, biroq bu turdagi funktsiyalarning haddan tashqari yuklanishini ta'minlaydi: har bir turdagi bitta funktsiya, bitta protsessor yordamida ularni bitta nom bilan izlash.

Fonksiyon qo'ng'iroqlari ish vaqti bo'yicha aniqlanadi.

C va C ++ da funktsiya chaqiruvi - nazorat qilish yo'li - kompilyatsiya vaqtida aniqlanadi. Hech qachon "qaror" yo'q.

Funktsiyalarning farqlari struct a'zolarining emas, balki ularning nomlaridan iborat.

Darhaqiqat, har bir tuzilish tartibida muhim farq bor. Ismlar turli joylarda. C kompilyatori ismlarni joylarga o'zgartiradi. Tarkibdan so'ng nomlar va hech qanday tip mavjud emas, bu joyning common1 nomi berilganligini bildiradigan hech narsa yoxud bir tarkibiy qism bo'lib qolgan. Xotira joyiga faqat bitta havola bor. O'zingiz niyat qilgan joyga murojaat qilishni ta'minlash uchun tilni to'g'ri ishlatishingiz kerak.

shuning uchun so'l noto'g'ri.

Dastlabki protsessor kompilyator raqamlarni ularning raqamlariga o'zgartirmasdan oldin nomlarni o'zgartirishga imkon beradi. Agar "ismga ko'ra" biror narsa qilishni xohlasangiz, makro shaharda yagona o'yin.

0
qo'shib qo'ydi
Ha, lekin bu haqiqiy tipga asoslangan holda chaqiriladigan funksiya kompilyatsiya vaqtida aniqlandi. Barcha aloqa kompilyator tomonidan qurilgan va runtime qo'llab-quvvatlamaydi. Dinamik ko'rinish - bu ko'plab "chayqalgan" nomlarni bir-birining orqasida yashirish va argumentlar turiga asoslangan holda jo'natish orqali (dasturchi foydasi va roziligi uchun) hosil bo'lgan illyuziya. Lisp, Smalltalk va Python kabi tillardan farqli o'laroq, dasturni nazorat qilishda ism-shariflarni o'zgartirishi mumkin.
qo'shib qo'ydi muallif James K. Lowden, manba
Bu keng tarqalgan noto'g'ri tushunchadir. "Ish vaqtida aniqlandi", qanday qilib? Virtual funktsiya yoki bajarilmasa, derleyici hech qanday ma'lumotni "bilmaydi". Derleyici, boshqarish orqali oqim yo'llarini hosil qiladi. Haddan tashqari yuklangan funksiya nom va argument turiga asoslangan holda chaqiriladi. Virtual funktsiya nom va argument turiga asoslangan holda chaqiriladi! Koenig qidirishdan tashqari, aralashmasigacha hech qanday farq yo'q. Ko'proq mashina, lekin statik jihatdan aniqlandi. Mantiqning 100% ikkilik: kutubxona yordami yo'q, tarjimon yo'q. Ish vaqti yo'q.
qo'shib qo'ydi muallif James K. Lowden, manba
C va C ++ da, funktsiya chaqiruvi - nazorat qilish yo'li - kompilyatsiya vaqtida aniqlanadi. Ish vaqti "qaror" yo'q. . Bu C uchun amal qiladi. Biroq C ++ virtual funktsiyasida ish stolida ko'rsatgich ko'rsatadigan ob'ektning haqiqiy turiga qarab aniqlanadi.
qo'shib qo'ydi muallif army007, manba
Funktsiyani haddan tashqari yuklab olish emas, balki asosiy sinfda aniqlangan virtual funktsiyalarini bekor qiluvchi boshlang'ich sinflar haqida gapirgan edim. Agar bir virtual funktsiyasi taglik sinfi ko'rsatgichi orqali chaqirilsa, u holda chaqiriladigan haqiqiy funksiya ish vaqtida aniqlanadi. Compiler, ko'rsatgich kompilyatsiya vaqtida qaysi ob'ektga ishora qilishini bilishning hech qanday usuli yo'q.
qo'shib qo'ydi muallif army007, manba

Men preprocessordan foydalanishni cheklash haqida noto'g'ri deb o'ylayman:

#include 

struct str1
{
    int common1;
    char common2;
    char *common3;
    long int aaaaaaaa;
};

struct str2
{
    char bbbb;
    char *common3;
    int common1;
    char common2;
};

struct str3
{
    char ccccccccc[200];
    int common1;
    char common2;
    int dddddddd;
    int eeeeeeee;
    char *common3;
};

#define somefunc(var) \
    printf("%d %c %s\n", var.common1, var.common2, var.common3);

int main()
{
    struct str1 var1 = {1,'a',NULL, 4};
    struct str2 var2 = {'b',NULL,2,'b'};
    struct str3 var3;
    var3.common1 = 3;
    var3.common2 = 'c';
    var3.common3 = NULL;


    somefunc(var1);
    somefunc(var2);
    somefunc(var3);

}

chiqdi:

1 a (null)
2 b (null)
3 c (null)
0
qo'shib qo'ydi
Siz aytmadingizmi - Fonksiyon qo'ng'iroqlari ish vaqti bo'yicha hal qilinadi? ? Bu sizning "ish vaqti" da qanday qaror qabul qilishingizga imkon beradi?
qo'shib qo'ydi muallif army007, manba
Buning o'rniga bitta kalit holatidagi foydalanuvchi kirilishini tekshirish va qanday funksiyani chaqirish kerakligini hal qilish kerak. @ Army007
qo'shib qo'ydi muallif J. Doe, manba