Sida 1 av 3

"generell pekartyp" i funktion?

Postat: 6 april 2011, 22:46:09
av jesse
Jag har två funktioner som sparar respektive läser data från eeprom.
Eftersom de ska kunna läsa och skriva vilka data som helst har jag gjort dem generella genom att man bara anger tre parametrar:

(a) adressen i SRAM
(b) adressen i EEPROM
(c) antal bytes.

Så här ser de ut:

Kod: Markera allt

	void ee_save(uint8_t* SRAM_pekare,uint8_t* EEPROM_pekare, uint8_t antal_bytes);
	void ee_read(uint8_t* SRAM_pekare,uint8_t* EEPROM_pekare, uint8_t antal_bytes);
Detta fungerar bra: internt i funktionerna kör jag igenom all data byte för byte.

Men jag stör mig lite på att jag måste omvandla pekarna till rätt sort vid varje anrop, dvs. skriva (uint8_t)* innan jag anropar. Så ett anrop kan se ut så här:

Kod: Markera allt

	ee_save((uint8_t*)&loggdata, (uint8_t*)&ee_loggdata, sizeof(loggdata));
Där 'loggdata' och 'ee_loggdata' är två identiska strukturer eller arrayer.

Nu vet jag att det finns något som heter "generell pekartyp" som jag tror jag kan använda mig av här, men jag är inte helt säker på hur jag gör rätt. Jag vill alltså kunna skriva så här:

Kod: Markera allt

	// deklaration
	void ee_save( void * SRAM_pekare, void * EEPROM_pekare, uint8_t antal_bytes);
	
	// anrop
	ee_save(&loggdata, &ee_loggdata, sizeof(loggdata));
En kanske löjlig "förbättring", men ändå...

Så nu funderar jag på hur jag ska kunna använda dessa "generella void-pekare internt i funktionen för att de ska bete sig som (uint8_t*)-pekare? Går pekarna att omvandla så att de blir uint8_t-pekare, eller måste jag skriva typomvandling på de ställen där de används?

Ett alternativ kan vara att jag skapar nya pekare inuti funktionen med rätt typ:

Kod: Markera allt

function ( void * argument_pekare ) {
	uint8_t * typad_pekare;
	typad_pekare = (uint8_t) argument_pekare;
	uint8_t value = *typad_pekare;
}
Problemet med pekare är ju att man inte alltid får några felmeddelanden om man gör fel...

Re: "generell pekartyp" i funktion?

Postat: 6 april 2011, 23:54:04
av swesysmgr
Typedefa en egen pekartyp istället om du vill ha snyggare kod? Jag är lite osäker på om jag förstått vad rationlaiseringen skall gå ut på?

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 08:49:28
av Icecap
Faktisk är det synnerligt vettigt att utföra denna castning! Grejen med att casta är just att man som programmör visar att man faktisk har koll på vad man gör så det är ett signal när man läser koden om att den som skrev det är på det rena med vad som göras.

Självfallet kan det bli fel ändå...

Men att välja en generell pekare för att spara lite knapptryckningar ville visa mig att man har börjat gena lite väl mycket och att kodningen generellt är slarvig.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 10:05:33
av jesse
Icecap: så om jag förstår dig rätt så tycker du koden blir sämre / mer svårbegriplig om jag ändrar något?

Jag tänker lite tvärt-om:

Om nu funktionen ska kunna ta emot vilka data som helst, så ska väl pekartypen reflektera det och inte tvinga att det ska vara uint8_t* ? Vad som sedan sker internt i funktionen är ju ointressant utifrån. Vad man som "användare" av funktionen vill veta är att det är OK att skicka t.ex. en array med 16-bitars integer eller en struct med blandat innehåll, så länge man håller reda på antal bytes, som är det tredje argumentet.

Med rätt dokumentation bara.

Kod: Markera allt

// void ee_save( void * SRAM_pekare, void * EEPROM_pekare, uint8_t antal_bytes);
//       void * SRAM_pekare    : pekar på den data som ska lagras
//       void * EEPROM_pekare : pekar på plats i EEPROM där data ska lagras
//       uint8_t antal_bytes     : anger hur många bytes data som ska överföras, 0-255
void ee_save( void * SRAM_pekare, void * EEPROM_pekare, uint8_t antal_bytes);
Jag vet inte om det bara är olika tyckande här, eller om det faktiskt finns någon praxis?

Just det där med hur man *brukar* eller *bör* göra inom programmering tycker jag är något man skriver väldigt lite om i läroböckerna. Böckerna koncentrerar sig till 99% på syntax och funktion. Mindre på hur det ska struktureras eller vilka sätt som är "lämpligast" ur läsbarhetssynpunkt.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 10:15:27
av Nerre
Det är väl i såna där lägen man vill använda C++ som om jag inte minns fel tillåter att en funktion kan ta emot flera olika typer?

Men grejen här är väl nu att när man skall anropa den där funktionen ska man ange antal bytes. Borde man då inte också typecasta pekaren till att peka på just bytes?

Annars riskerar man ju att nån som ska skicka en array av 16-bitars integers bara räknar antalet poster i arrayen och glömmer att multiplicera med två. Om man "tvingas" casta pekaren till unit8_t så påminns man också om att antalet skall vara bytes.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 10:56:37
av johano
Nja, i C++ så blir det olika funktioner då det är namn + argumenten som utgör det "unika" för funktionen:

Kod: Markera allt

void Func(long* a) { }
void Func(char* c) { }
är alltså två helt olika funktioner även fast de har samma namn.
(De kan ju sedan "internt" använda samma bakomliggande logik vilket är rätt vanligt för att
åstadkomma det efterfrågade)

Ett snyggare (tycker iaf. jag) sätt att hantera problemet i C++ är att
använda templates, typ såhär

Kod: Markera allt

template<typename T> void Func(T *pt)
{
  // du kan använda sizeof(T) för att få reda på storleken i bytes på T
}

och den kan användas på följande sätt:

Kod: Markera allt

long *a;
char *c;

Func<long>(a);
Func<char>(c);

/johan

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 11:02:50
av johano
För att återgå till topic så är väl standard för C att använda void* just för detta ändamål,
se t.ex. på free() och realloc() i CRT.

/johan

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 13:34:38
av Borgen
Borttaget för att inte förvilla.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 13:43:02
av AndLi
Borgen: I vilken C standard hittar du det?
Min C kompilator (Gcc 4.4.1) och jag verkar överrens om att överlagring inte är standard C

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 13:45:27
av Borgen
Så ville jag minnas jag lärde mig det. Men det har hänt att jag har haft fel förut.
Måste kolla upp det.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 13:49:06
av Borgen
jesse skrev:

Kod: Markera allt

void ee_save( void * SRAM_pekare, void * EEPROM_pekare, uint8_t antal_bytes);
Detta kan ge kompilatorvarningar när Du anropar funktionen utan att casta om argumentet till void*. Det innebär att för att slippa varningar kan Du behöva casta om i alla anrop ändå. Alltså casta om till uint8_t eller till void*. Vilket blir tydligast?

Om detta ger kompilatorvarningar eller ej beror på kompilatorn. Men för att koden ska vara ordenligt dokumenterad bör argumenten i funktionsanropet vara av samma typ som funktionen tar emot. Det visar, som Icecap påpekade, att programmeraren har koll på vad denne gör.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 14:11:52
av johano
Borgen: vilken kompilator kör du med??

I alla C-kompilatorer jag använt så kan alltid en void* tilldelas alla möjliga adresser utan castning(!)

Kod: Markera allt

void f()
{
	int a;
	char c;
	long l;
	struct _s
	{
		int a;
		int b;
	} s;

	void *p;

	p = &a;
	p = &c;
	p = &l;
	p = &s;
}
/johan

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 14:18:08
av Borgen
johano: Använde en anpassad utvecklingsmiljö. Kollade inte upp vilken kompilator den använde sig av.

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 16:24:51
av jesse
tanken med void* är väl att den ska kunna svälja vilken typ som helst?
Jag får inga varningar i alla fall. (AVR-GCC).

Det fåniga bara är att funktionen måste ha två pekare till (och två rader mer) bara för att jag vill ha void* som argument:

Kod: Markera allt

//läs in ett antal bytes från eeprom till sram
void ee_read(void* SRAM_pekare,void* EEPROM_pekare, uint8_t antal_bytes) {
		uint8_t* SRAMp = SRAM_pekare;
		uint8_t* EEp  = EEPROM_pekare;
	for (uint8_t i=0; i < antal_bytes; i++) 
		*SRAMp++ = eeprom_read_byte(EEp++);
}

Re: "generell pekartyp" i funktion?

Postat: 7 april 2011, 16:35:02
av Zeela
Borde väl gå att göra castingen inne i funktionen...
Typ så här:

Kod: Markera allt

//läs in ett antal bytes från eeprom till sram
void ee_read(void* SRAM_pekare,void* EEPROM_pekare, uint8_t antal_bytes) {
   for (uint8_t i=0; i < antal_bytes; i++)
      *(uint8_t*)SRAM_pekare++ = eeprom_read_byte((uint8_t*)EEPROM_pekare++);
}