Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Typedef struct ongelma

Sivun loppuun

Tumpelo [19.06.2006 09:57:29]

#

typedef struct //rivi 17
{
    float x, y, z;
    float u, v;
} vertex;

typedef struct //rivi 23
{
    vertex vertex[3];
} triangle;

typedef struct //rivi 28
{
    int numTriangles;
    triangle *triangle;
} sector;

Tuo koodinpätkä aiheuttaa seuraavat herjaukset:

:25: error: declaration of ‘vertex triangle::vertex [3]’
:18: error: changes meaning of ‘vertex’ from ‘struct vertex’
:31: error: declaration of ‘triangle* <anonymous struct>::triangle’
:24: error: changes meaning of ‘triangle’ from ‘struct triangle’

Mitä tuolle keksisi tehdä?

Metabolix [19.06.2006 10:07:02]

#

Ei pitäisi käyttää tyypin nimeä muuttujan nimenä. Tuossa nyt tapahtuu suunnilleen sama kuin jos määrittelisit näin:
int int = 10;
Kääntäjä ei voi siis tietää, viittaatko vertexillä tyyppiin vai vertex-nimiseen muuttujaan. Hyvä tapa on merkitä tyypit jotenkin. C:ssä melko perinteisesti käytetään t_tyyppi-merkintää, kuten selviää standardikirjastoistakin: t_time, t_clock, eli t_vertex. Linuxin kernelin ohjelmointityylissä kielletään käyttämästä typedefejä (tai defineä) structien nimeämiseen, jolloin tyypin nimeksi tulee aina kirjoittaa struct tyyppi. Tietenkin tällöin pitää olla käytössä oikeasti C-kääntäjä, koska C++ sotkee tuonkin käytännön. itse merkitsen tyypit T-kirjaimella (tai osoitinten tapauksessa P-kirjaimella) Pascalista oppimaani tapaan: TVertex. Tätä monet C:n käyttäjät pitävät huonona tapana, mutta kukin koodaa tavallaan.

Tumpelo [19.06.2006 10:19:18]

#

Okei, asia selvä. Vielä kuitenkin ilmeni yksi minulle tuntematon ongelma seuraavasta koodinpätkästä:

sector1.triangle = malloc(numTriangles * sizeof(Ttriangle));

numTriangles on ihan int luku, ja sector1.triangle on sama on sama kuin tuossa ensimmäisessä koodissa näkyy.

Ainiin se virheilmoitus unohtui. ^^

invalid conversion from ‘void*’ to ‘Ttriangle*’

Metabolix [19.06.2006 10:24:08]

#

Sinun koodissasi se t_ näyttäisi paljon selkeämmältä kuin T, kun käytät muutenkin pieniä kirjaimia enimmäkseen. :)

Tarvitset tyypinmuunnoksen muuttaaksesi muistinkäsittelyfunktion antaman tyypittömän osoittimen osoittimeksi tiettyyn tyyppiin. (Toiseen suuntaan muunnosta ei erikseen tarvita.) Eli sulkuihin laitetaan tyyppi, joksi sulkujen jälkeinen asia eli mallocin palautusarvo halutaan muuttaa.

int **osoitin = (int **) malloc(sizeof(int *));
osoitin[0] = (int *) malloc(sizeof(int));
free(osoitin[0]);
free(osoitin);

Tumpelo [19.06.2006 13:13:13]

#

Öh, en nyt ihan käsittänyt noita kahta ensimmäistä riviä, vaikka aivojen kuormitus yrityksen aikana lähenteli 110%. Pitääkö tuo eka rivi siis kirjoittaa vaikka näin:

int Kana = (int) malloc(sizeof(t_triangle));

Onko siis tuon jälkeen int Kanassa tuon t_trianglen koko ihan inttinä?

Tuosta toisesta rivistä en käsittänyt mitään... :D

Metabolix [19.06.2006 13:16:51]

#

Eieiei. Esimerkissä siis varasin int**-muuttujaan int*:n ja siihen yhden intin.

t_triangle *Kolmio = (t_triangle *) malloc(sizeof(t_triangle));

Tumpelo [19.06.2006 13:21:24]

#

Ööh... Ehkä tämä kuuma ilma on tehnyt tehtävänsä, mutta minä jokatapauksessa olen pudonnut kärryiltä. Mitä tuo koodi nyt niinku tallentaa tuohon t_triangle *Kolmio -juttuun? Ja mitä tuo *Kolmio tuossa tekee?

Metabolix [19.06.2006 13:33:40]

#

Tumpelo kirjoitti:

typedef struct
{
    int numTriangles;
    t_triangle *triangle;
} t_sector;

Sieltä löytyy ihan omasta koodistasi se mainittu t_triangle *Kolmio.

Muistinvarauksessa varatun muistin määrää ei tallenneta minnekään ohjlemasi saataville, joten sitä pitää itse kuljettaa muuttujassa. Sitä varten tuossa t_sector-structissa on numTriangles-muuttuja. Todennäköisesti siis teet käytännössä jotenkin tähän tapaan:

t_sector sektori;
sektori.numTriangles = 1000; /* Varmaankin luet sen tiedostosta oikeasti... */
sektori.triangle = (t_triangle *) malloc(sektori.numTriangles * sizeof(t_triangle));

Tumpelo [19.06.2006 13:40:28]

#

Noh, ymmärryksen puolella vielä ongelmia, mutta sain toimimaan joten ehdin perehtyä tuohon kohtaan sitten myöhemmin.

koo [20.06.2006 13:20:15]

#

Usein syntaksi jo estääkin tyyppien nimien käytön muuttujaniminä, mutta vaikkei niin tapahtuisikaan, tapaa kannattaa välttää, sillä se tekee koodista epäselvää luettavaa.

C:ssä mallocin paluuarvoa ei kannata (lähes) koskaan castata, sillä se piilottaa nekin tyyppivirheet, jotka kääntäjä muuten havaitsisi.

Jos koodin on tarkoitus olla C++:aa, silloin koko juttu kannattaa hoitaa eri tavalla: ei todellakaan typedefejä eikä ensinkään mallocia.

Metabolix [20.06.2006 23:14:26]

#

Joo, tosiaan C-koodi kannattaa tallentaa .c-tiedostoon ja kääntää gcc:llä g++:n sijaan, niin se toimii C:n standardien mukaan. IDEt useimmiten päättelevät tiedostopäätteen perusteella, kumpaa kääntäjää pitää käyttää, ja tallentaessa tahtoo nykyään tulla C++:n tiedostopääte oletuksena, jos ei erikseen päätettä kirjoita.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta