Ett annat C-kods problem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47020
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Ett annat C-kods problem

Inlägg av TomasL »

Funderar på om detta är tillåtet i ANSI-C, har ej hittat nått vettit svar i K&R:

Kod: Markera allt

void func(void)
    {
       char a[20];
       a[]=.................................; // bry er int om denna rad, är lat bara :) 
       if (a[4])
                DWORD *p=dworddata;
       else
                FLOAT *p=floatdata;
       .....Övrig kod
    }
Gissar att det borde vara ok.
Vad jag vill göra är föjande:
Via serieporten tar jag emot ett datagram, en viss byte i datagrammet talar om längden på datagrammet, 8 eller 16 byte.
Jag använder 2 olika strukturer, ett för det långa och ett för det korta datagrammet.
Det min serierutin tar emot datgrammet och placerar det i en temporär matris "a" i exemplet ovan
sedan, beroende på längden skall datagrammet kopieras över till resp struktur så jag kan använda det sedan.

Frågan är om ANSI-C accepterar att jag deklarerar och samtidigt tilldelar pekaren "p" i en if-sats?

Det borde fungera tycker jag, men?

Nån som har nån kommentar.
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Jag är ganska säker på att man inte kan deklarera variabler alls "mitt i" programmet i ANSI-C.

Du får antagligen deklarera två olika varibler i början av programmet.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

En av sakerna som blev adderat i C++ var möjligheten att deklarera variabler mitt i. Dessutom är det en annan sak som gör att det inte fungerar även i C++:

Kod: Markera allt

void func(void)
    {
       char a[20];
       a[]=.................................; // bry er int om denna rad, är lat bara :)
       if (a[4])
                DWORD *p=dworddata;
       else
                FLOAT *p=floatdata;
  // Precis när if/else lämnas försvinner det lokala scopet för dessa variabler
       .....Övrig kod
    }

Alltså kan du istället deklarera:
union
  {
  DWORD *p_dw;
  FLOAT *p_fl;
  } Common;
Då kan du komma åt 2 variabler som är exakt lika:
Common.p_dw som DWORD-pekare
Common.p_fl som FLOAT-pekare
De delar minnesplats och om du sätter den ena sätter du per definition den andra också.

Men egentligen kan det kvitta totalt med denna uppdelning, en pekare är en pekare!
Deklarera alltså
void * p;
och använd den, när du senare ska räkna och kompilern gnäller får du cast'a den, FLOAT-pekare = (FLOAT*)p och DWORD-pekare = (DWORD*)p
Användarvisningsbild
Ulf
Inlägg: 399
Blev medlem: 15 februari 2006, 14:04:03

Inlägg av Ulf »

Så som koden kan tolkas så har Icecap helt rätt, du löser det med en union.
Det slulle iofs gå med void* p, men då blir det jobbigt att typecasta hela tiden.

Säger inte ansi-c att deklaration av en variabel ska ske i början av ett block?

Tex

void func(void)
{
char a[20];
...
if( a[0] == '1' )
{
int A;
/* gör något med A */
...

/* Aslutar existera när man är ute ur blocket */
}
}

Sen har vi ju POSIX också...
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47020
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Inlägg av TomasL »

Har funderat på en union, men, iofs var exemplet lite dåligt, eftersom pekaren skall peka på en av två olika strukturer med olika antal medlemmar.
Med en union blir jag fortfarande tvungen att adressera resp struktur individuellt.

Tror lösningen med att typecasta en void pekare är en bättre lösning.
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg av Millox »

Deklareringssättet är ANSI C endast i standarden C99, inte i den gamla standarden. GNU CC använder dock inte C99 som standard, men andra kan göra det.

Som Icecap säger är det dock scopet för variablerna som gör att det inte kommer funka. Använd istället void* och håll reda på hur du använder variabeln genom att casta den rätt istället; om du prompt måste lösa det med variabler med samma namn.

Alltså:

void *p = NULL;

(DOUBLE*)p = apa;
(FLOAT *)p = bepa;
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47020
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Inlägg av TomasL »

Orsaken är att jag vill spara kod-utrymme.

Känns lite onödigt att dubblera funktionen, därför vill jag göra på detta sättet.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Inte sparar du någon kodplats på det vis, du sparar bara lite RAM-minne (en pekare).
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47020
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Inlägg av TomasL »

Borde göra det.


I princip bör det bli så här:

Kod: Markera allt

void *p;
if (a[4]=8)
    (shortstruct*) p=shorstruct;
else (longstruct*) p=longstruct;

strcopy(p, &a);


Annars blir det så här:
shortstruct *p;
lonstruct *p1;
if (a[4]=8)
    strcopy(p, &a)
else
    strcopy(p1,&a)

Det borde rimligtvis spara lite tycker jag.
eftersom pekaren och a[] är lokala tar de inte upp nån plats i ram, skillnaden blir att jag sparar in ett hopp till strcopy och därmed en del kod som annars går åt för att skapa hoppet, stackhantering mm.
Mupp
Inlägg: 134
Blev medlem: 25 februari 2006, 10:30:38
Ort: Linköping

Inlägg av Mupp »

Kompilatorer är fantastiska saker. Vilket innebär att dom inte alltid gör som man tänkt. Har du testat så att du vet att det spar det du tänkt spara? Det känns som att -Os (eller motsvarande) kommer påverka mängden programminne mer är "fulhack", om du ursäktar. Optimering brukar gå sämre om man försöker förvirra kompilatorn, vilket inte är alltför svårt, för att inte tala om hur förvirrad man själv blir när man läser det en vecka efter man skrivit det. Mitt råd är att testa båda och avgöra om det är värt det, jag är beredd att sätta din nästa månadslön på att det inte lönar sig alltför mycket.

Edit, syftningsfel.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47020
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Inlägg av TomasL »

Kod: Markera allt

	char tempdata[21];
	char *p;
	char test=tempdata[3];
	LONGSTRUCT *pl=&longdata;
	SHORTSTRUCT *ps=&shortdata;
	
	if (test==15)
		p= &shortdata.v[0];
	else  p= &longdata->v[0];
	vstrcpy(p, tempdata);
	
	//den andra varianten
	if (test==15)
		strcpy(ps->v, tempdata);
	else strcpy(pl->v, tempdata);
Jag blev tvingad att deklarera typerna som en union mellan de egentilga strukturerna och en char v[].

Den första varianten tar 60 byte totalt och den andra 68 byte totalt. (11%) besparing av kodminne, vilket är rätt mycket, med tanke på PICarnas begränsade utrymme

Edit: Det skiljer 12 byte mellan de olika metoderna.
Skriv svar