"generell pekartyp" i funktion?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

"generell pekartyp" i funktion?

Inlägg 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...
Användarvisningsbild
swesysmgr
Inlägg: 14819
Blev medlem: 28 mars 2009, 06:56:43
Ort: Göteborg

Re: "generell pekartyp" i funktion?

Inlägg 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å?
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: "generell pekartyp" i funktion?

Inlägg 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.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: "generell pekartyp" i funktion?

Inlägg 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.
Nerre
Inlägg: 27143
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: "generell pekartyp" i funktion?

Inlägg 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.
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: "generell pekartyp" i funktion?

Inlägg 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
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: "generell pekartyp" i funktion?

Inlägg 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
Användarvisningsbild
Borgen
Inlägg: 39
Blev medlem: 21 januari 2009, 17:50:43
Skype: henrikborg
Ort: Botkyrka
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg av Borgen »

Borttaget för att inte förvilla.
Senast redigerad av Borgen 7 april 2011, 14:30:28, redigerad totalt 1 gång.
Användarvisningsbild
AndLi
Inlägg: 18097
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg 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
Användarvisningsbild
Borgen
Inlägg: 39
Blev medlem: 21 januari 2009, 17:50:43
Skype: henrikborg
Ort: Botkyrka
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg 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.
Användarvisningsbild
Borgen
Inlägg: 39
Blev medlem: 21 januari 2009, 17:50:43
Skype: henrikborg
Ort: Botkyrka
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg 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.
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: "generell pekartyp" i funktion?

Inlägg 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
Användarvisningsbild
Borgen
Inlägg: 39
Blev medlem: 21 januari 2009, 17:50:43
Skype: henrikborg
Ort: Botkyrka
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg av Borgen »

johano: Använde en anpassad utvecklingsmiljö. Kollade inte upp vilken kompilator den använde sig av.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: "generell pekartyp" i funktion?

Inlägg 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++);
}
Zeela
Inlägg: 176
Blev medlem: 28 augusti 2008, 11:23:49
Ort: Åtvidaberg
Kontakt:

Re: "generell pekartyp" i funktion?

Inlägg 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++);
}
Skriv svar