Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: CodeBlocksin varoituksesta

Sivun loppuun

DumTom [09.01.2011 08:34:04]

#

struct KIRJOITUS
{
// structissa kirjotteluun liittyvää enemmänkin
char VIRKE14[30];
};
KIRJOITUS T;

// Kutsuva funktio
NextText("%2YOU SEE",0);

void NextText(char t[],char mode)
{
if (mode==0)
   {
   strcpy(T.VIRKE14,t);
   }
if (mode==1)
   {
   strcat(T.VIRKE14,t);
   }
}

Mistä seuraava varoitus johtuu?
Näitä samoja varoituksia saan 144 kappaletta.

D:\UHO\Indoor\look.h|181|warning: deprecated conversion from string constant to 'char*'|

eq [09.01.2011 12:39:45]

#

C:ssä (ja C++:ssa) lainausmerkeissä kirjoitettu merkkijonovakio (engl. "string literal") on anonyymi taulukko tyyppiä const char[N] missä N on merkkijonon pituus + 1 (merkkijonon päädyn osoittavaa nollatavua varten).

Sijoittamalla tämän merkkijonon osoitteen osoittimeen tyyppiä char* menetät const-määreen. Historiallisista syistä johtuen tämä ei ole virhe, mutta monet kääntäjät kuitenkin huomauttavat asiasta. Merkkijonovakiota ei missään tapauksessa saa muuttaa määrittelyn jälkeen - tämän yrittäminen johtaa ohjelman määrittelemättömään toimintaan (engl. "undefined behavior") - useissa tapauksissa ohjelman kaatumiseen (ja teoreettisissa tapauksissa vieläkin ikävämpiin lieveilmiöihin, kuten virhetoimintaan jossain muussa ohjelman osassa).

Korjaa virhe tässä tapauksessa kirjoittamalla funktion prototyyppi kuten

void NextText(const char t[], char mode)

Huomioithan, että funktiolle ei voi välittää taulukkoa. Yllä oleva vastaa täysin seuraavaa prototyyppiä:

void NextText(const char* t, char mode)

Metabolix [09.01.2011 14:25:39]

#

Kyseessä ei suinkaan ole teoreettinen ongelma, vaan odottamattomia vaikutuksia saa helpostikin. Seuraava testi on ajettu Linuxissa GCC 4.5.2:lla.

#include <stdio.h>
#include <string.h>

static void muuta(const char* str) {
	// Muunnos char*-tyyppiin ja laiton muokkaus.
	char* tmp = (char*) str;
	tmp[strlen(str)] = '!';
}

int main() {
	// Muutetaan tekstiä ja tulostetaan sama teksti.
	muuta("ABCDEFG");
	puts("ABCDEFG");
	return 0;
}
gcc b.c && ./a.out
# Ohjelma kaatuu: Segmentation fault
gcc b.c -Wl,-N -static && ./a.out
# Tulostaa: ABCDEFG!FATAL: kernel too old
# Ei kuitenkaan kaadu, vaan pelottava teksti on sattumaa.
gcc b.c -Wl,-N -static -O && ./a.out
# Tulostaa: ABCDEFG

Mielenkiintoista, että kun optimointi on käytössä, GCC poistaa koko muuta-funktion. (Jos funktio ei ole static eikä inline, tarvitaan -O3, jotta GCC ajaa riittävän tarkan analyysin; alemmilla asetuksilla saadaan keskimmäinen tulos.)

eq [09.01.2011 14:43:25]

#

Metabolix kirjoitti:

Kyseessä ei suinkaan ole teoreettinen ongelma, vaan odottamattomia vaikutuksia saa helpostikin. Seuraava testi on ajettu Linuxissa GCC 4.5.2:lla.

Sanavalinta oli ehkä huonohko, mutta perustelen sitä sillä, että hain lauseella hieman salakavalampia ongelmia kuin "saman" merkkijonon muuttuminen myöhemmin ohjelmassa.

DumTom [09.01.2011 17:02:22]

#

Eipä warningit hävinny mihinkään vaikka laitoin constin ja char *t?????

eq [09.01.2011 17:05:34]

#

DumTom kirjoitti:

Eipä warningit hävinny mihinkään vaikka laitoin constin ja char *t?????

Varoitusten, jotka viittasivat tämän funktion tällä tavalla virheelliseen käyttöön, olisi pitänyt poistua. Koodissa on mahdollisesti muita samanlaisia tai erilaisia virheitä, mutta kristallipalloni ei suostu enää kertomaan että missä ja minkälaisia (ts. näkemättä koodia ja näkemättä virheilmoituksia on mahdotonta sanoa).

Huomioithan, että funktion argumenttilistaa pitää muuttaa sekä esittelyssä, että varsinaisessa määrittelyssä, sikäli kun molemmat koodissa esiintyvät. Esimerkiksi

void NextText(char t[], char mode);
/* ... myöhemmin, muualla ... */
void NextText(char t[], char mode)
{
    /* itse funktio */
}

Tulee muuttaa esim. seuraavasti:

void NextText(const char t[], char mode);
/* ... myöhemmin, muualla ... */
void NextText(const char t[], char mode)
{
    /* itse funktio */
}

Metabolix [09.01.2011 17:23:36]

#

eq kirjoitti:

Sanavalinta oli ehkä huonohko, mutta perustelen sitä sillä, että hain lauseella hieman salakavalampia ongelmia kuin "saman" merkkijonon muuttuminen myöhemmin ohjelmassa.

Ei ollut tarkoitukseni moittia hyvää selostustasi, vaan suuntasin konkreettisen esimerkin enemmänkin DumTomille. Tuo esittämäni tekstin muuttuminen on kieltämättä Linuxissa edelleen aika teennäinen juttu (vaatii juuri oikeat käännösasetukset), vaikka jossain muussa järjestelmässä (DOSissa ainakin, heh) ongelma onkin todellinen. Linuxissa tuskin pääsee kovin helposti tapahtumaan muuta kuin segfault, ellei ohjelmassa ole samaan aikaan jotain muutakin merkittävää bugia.

DumTom [09.01.2011 18:01:52]

#

Sain warningit häviämään. Siellä oli useassa otteessa noita constin puutteita.


Sivun alkuun

Vastaus

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

Tietoa sivustosta