C-pointteriongelma

Pointteri p osoittaa struktuurin alkioon. Miten saan muutettua sen osoittimeksi itse struktuuriin? Vieläpä standardi-C:llä, jos mahdollista!
10464
Äänestä

Muut lukivat myös

Vastaukset 10

Vanhimmat

Tarkoitko siis struktuurilla struct-tietuetta? Pitäisi tietää mihin alkioon se pointteri osoittaa. En usko, että on mitään geneeristä kikkaa, joka toimii joka tilanteessa. Parempi koodata se niin, ettei moista muunnosta tarvi.

Osoitin structiinhan on sama kuin osoitin sen ensimmäiseen alkioon, joten siinä erikoistapauksessa se onnistuu. Koodinpätkä selkeyttäisi ongelmaa huomattavasti.

Äänestä

Jos tiiät mihin alkioon p osoittaa lasket monettako struktuurin tavua se osoittaa ja muutat pointteria niin että se osoittaa ko. tavumäärän taaksepäin.. noin periaatteessa. Eri asia kannattaako tommosia säätöjä edes miettiä ei kuulosta kovin loppuunsuunnitellulta

Äänestä

Mikäli tajusin oikein, olette tekemässä jotain seuraavaa (C :aa C:lla):

struct A {
Some information;
void (*funkPtr)(struct A *a,Params *whatEver);
};

struct B {
struct A first; //HUOM alussa
//some extra information
};

nyt B:n osoittimesta saa osoittimen aika helposti
ja typecastaus onnistuu. KUITENKIN, jos first ei
ole alussa, niin homma menee monimutkaisemmaksi.
Joutuu laskemaan biteittäin, miten monta bittiä pitää vähentää alusta. Tämä on aika tuskaista ja
ankeaa puuhaa. Tuo ylläolevakin esimerkki rikkoo C:n pyhintä ansi-standardia, mutta toiminee käytännössä.

Eräs vaihtoehto (kauniskin :) tietty on, tehdä seuraava jäynä:

struct Owner;

struct Member {
struct Owner *owner;
//some data
};


struct Owner {
//some data
struct Member *member;
};

//alustaa tiedon oikein
//kaksisuuntaiset linkit on aina hieman
//suxoreita
void Owner_setMember(struct Owner *owner, struct Member *member) {
owner -> member = member;
member -> owner = owner;
}

struct Owner* Member_getOwner(struct Member *member) {
return member -> owner;
}

tähän tapaan... (Kannattaa tosiaan harkita vielä.
Olioiden palauttaminen ei kuulu olio-ohjelmointiin, eikä kai funktionaaliseenkaan tyyliin)

Äänestä

#include

typedef struct
{
char data;
int data2;

} Rakenne;


Rakenne *HaeRakenne(int *data)
{
Rakenne Tmp; /* antaa kääntäjän laskea :) */

/* Lasketaan offset tavuina */
int off = &Tmp.data2 - &Tmp; /* kääntäjä valittaa */


return (Rakenne *)(data - off);
}

int main (void)
{
Rakenne Tmp;
Rakenne *pTmp;

int *d = &Tmp.data2;

pTmp = HaeRakenne(d);

if (pTmp == &Tmp)
{
puts("onnistui");
}
return 0;
}

Äänestä
  • Asiallinen yritys, mutta esimerkkisi toimii korkeintaa "onnellisten tähtien alla", kun struktuurin aligment sattuu menemään sopivasti. Kokeile vaikka antaa kääntäjällesi optio, jolla struktuurit pakataan (ts. jäsenten väliin mahdollisesti jäävä tyhjä tila poistetaan) ja esimerkkiisi lakkaa toimimasta saman tien.

    Jos "kääntäjä valittaa", se on jo yleensä merkki siitä, ettei homma mene aivan standardin mukaan, vaikka sattuisikin toimimaan.

    Äänestä

  • Sinivuokko kirjoitti:

    Asiallinen yritys, mutta esimerkkisi toimii korkeintaa "onnellisten tähtien alla", kun struktuurin aligment sattuu menemään sopivasti. Kokeile vaikka antaa kääntäjällesi optio, jolla struktuurit pakataan (ts. jäsenten väliin mahdollisesti jäävä tyhjä tila poistetaan) ja esimerkkiisi lakkaa toimimasta saman tien.

    Jos "kääntäjä valittaa", se on jo yleensä merkki siitä, ettei homma mene aivan standardin mukaan, vaikka sattuisikin toimimaan.

    offsetof() näyttää toimivan samalla periaatteella, mutta siinä on käytössä NULL osoitin eikä muutujaa. Ja segmentointi varmasti sotkee lisää. Huono ratkaisu...

    Tuota aligment ongelmaa en ymmärrä, eikös väli ole sama kun osoitteilla pelataan (kääntäjän luulisi tietävän jäsenten välit) ?

    Äänestä

  • Jepuli kirjoitti:

    offsetof() näyttää toimivan samalla periaatteella, mutta siinä on käytössä NULL osoitin eikä muutujaa. Ja segmentointi varmasti sotkee lisää. Huono ratkaisu...

    Tuota aligment ongelmaa en ymmärrä, eikös väli ole sama kun osoitteilla pelataan (kääntäjän luulisi tietävän jäsenten välit) ?

    Offsetof on osa standardia ja sen vuoksi se "toimii". Sen sijaan standardi ei määrittele miten offsetof laskutoimituksen tekee.

    Jos kääntäjäsi käyttää NULL-osoitinta ja vähennyslaskua, jokin toinen kääntäjä johonkin toiseen ympäristöön, kenties, saattaa käyttää jotakin aivan muuta tapaa.

    Offsetof on standardin mukainen ja siirrettävä. NULL-osoittimen ja vähennyslaskun käyttö ei sitä ole.

    Alignment (valitan painovirhepaholaista ed. viestissäni) on hauska juttu varsinkin näissä "isoissa" koneissa. Alignment-vaatimusten vuoksi dataelementit sijoitetaan muistissa esim. parilliseen tai neljällä jaolliseen osoitteeseen. Näin ollen jos struktuurissa on peräkkäin vaikkapa char- ja long-tyyppiset muuttujat, näiden väliin jää todennäköisesti yksi tai kolme tavua tyhjää tilaa (gap). Tämän vuoksi struktuurin koko ei välttämättä ole sama kuin sen elementtien yhteenlaskettu koko.

    Intelin prossut toimivat (tiettävästi edelleen) ilman alignment-säätöjäkin, mutta suorituskyky heikkenee. PC-maailman ulkopuolelta löytyy paljon ympäristöjä, joissa alignment on vaatimus, ei toivomus.

    Äänestä

Tällainen "pointteriongelma" saattaa todellakin tulla eteen vaikkapa data-elementejä ketjutettaessa. Ongelmaan pitää löytyä myös standardin mukainen ratkaisu.

Edellisissä vastauksissa olikin jo kerrottu, että osoitinta (p) täytyy vähentää struktuurissa edellä olevien jäsenten kokoa vastaavasti. Tähän tarkoitukseet on standardissa määritelty oma työkalunsa, makro nimeltä offsetof (stddef.h). Makro palauttaa struktuurin nimetyn jäsenen offsetin ts. "sijainnin" ottaen huomioon alignmentin jne.

Offsetti on byteinä, eikä standardi tunne sellaista datatyyppiä. Tässä kohtaa onkin pakko tehdä pieni oletus. Helpoin sellainen on olettaa, että char (ts. sen koko) on sama kuin byte. Mutta ehkä sittenkin varmistamme asiaa niin pitkälle kuin mahdollista...

p on siis osoitin struktuurin s jäseneen j.
Osoitin (q) ko. struktuuriin lasketaan näin:

q = (struct s *)((char *)p - offsetof(s,j)/sizeof(char));

Tiedän, ettei tuokaan yhtälö toimi kaikissa ympäristöissä. 10 kpl laatikko tyhjiä CD-R-levyjä ensimmäiselle, joka vastaa ja kertoo mikä yhtälössä on vikana ja mitä ympäristöä tarkoitin! Toinen 10 kpl laatikko sille, joka pistää yhtälön paremmaksi. Sähköpostiosoite mukaan.

Äänestä
  • ...kun tämä viestiketju putoaa pois ohjelmointipalstan 1. sivulta.

    Äänestä

Mitä ilmeisemmin ongelma on aivan muualla, eli suunnitteluvaiheessa, jos tuollaista täytyy jo alkaa suunnittelemaan. Miksi yleensäkään edes haluat tehdä tuollaista ? Vaikuttaa purkkaviritelmältä, joka ei taatusti tule toimimaan kuin tietyssä alustassa tietyillä arvoilla tiettynä kellonaikana, eli keskiyöllä täydenkuun aikaan, jos silloinkaan.

void-osoittimen käyttöä voisi testata, mutta parempi vain suunnitella koko homma kunnolla alusta asti.

Äänestä

Kommentoi aloitusta


Iso Ansi kirjoitti:

Pointteri p osoittaa struktuurin alkioon. Miten saan muutettua sen osoittimeksi itse struktuuriin? Vieläpä standardi-C:llä, jos mahdollista!

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu