return value pointer

Status
Niet open voor verdere reacties.

HelpElec

Gebruiker
Lid geworden
6 mrt 2013
Berichten
102
Beste allemaal,

Ik heb een functie waarin een de waarde van een Uint8 omgezet wordt naar ASCII-karakters. De return waarde van deze functie is een Uint8 Return[3] waarin de ASCII-karakters staan.
Je kunt geen array als return value hebben (als ik het goed heb), dus ziet mijn functie er nu zo uit:

Code:
U8 *Uint8_to_ASC(Uint8 Val)
{
	Uint8 i, Value, Temp, Divider;
	Uint8 Rtrn[3];

	Divider=100;
	Value=Val;
	for(i=0;i<3;i++)
	{
		Temp=Value/Divider;
		Rtrn[i]=Temp;
		Rtrn[i]+=48;  //vanaf Hex 0x30, Dec 48 begint karakter '0'
		
		Value-=Temp*Divider;
		
		Divider/=10;
	}
	return &Rtrn[0];
}

Alleen heb ik als probleem dat als ik mijn function-call doe:

Code:
Uint8 *AscArr;

AscArr = &Uint8_to_ASC(Getalletje);

krijg ik een error bij het compileren:
take address of rvalue: operator `unary&'.
Haal ik de & weg voor de function-call, compileert hij alleen krijg ik foute waarden.

Hoe los ik dit op?
Voorbaat dank!
 
Wat aanvullende info:

Ik gebruik SOFTUNE Workbench V30L36 van Fujitsu
 
Op deze manier compiled het hier: using namespace std;
uint8_t* Uint8_to_ASC(uint8_t Val)
{
uint8_t i, Value, Temp, Divider;
uint8_t *Rtrn[3];

Divider=100;
Value=Val;
for(i=0;i<3;i++)
{
Temp=Value/Divider;
Rtrn=&Temp;
Rtrn+=48; //vanaf Hex 0x30, Dec 48 begint karakter '0'

Value-=Temp*Divider;

Divider/=10;
}
return Rtrn[0];
}
int main(int argc, const char * argv[])
{

// insert code here...
cout << "Hello, World!\n";
uint8_t *value;
value = Uint8_to_ASC((uint8_t)49);
cout << value << endl;
return 0;
}

Maar wat het moet doen snap ik niet echt.
 
Okay bedankt,

Het is voor een RS232-bus. Een UInt8 moet als ASCII-string naar een computer gestuurd worden.
Ik heb het opgelost door van Uint8 Rtrn[3] globale variabelen te maken. Dit werkt prima.
 
Roy, het kan misschien wel compilen, maar dat iets compileert wit l nog niet zeggen dat het ook klopt. Je houdt er geen rekening mee dat een pointer een verwijzing naar een geheugenadres is en dat die pointer in dit geval alleen binnen de scope van die methode een context heeft. Na het verlaten is het dan ook ongedefinieerd (wat je voor waarde krijgt hangt er namelijk van af wat er zich op dat moment op het adres bevindt waar die pointer naar verwijst). Indien je toch een pointer vanuit een method wilt returnen dan zal je die op de heap moeten aanmaken (en later dus ook weer vrijgeven, want anders krijg je lekken). Je weet het verschil tussen geheugen op de stack declaren en op de heap?


Een mogelijke oplossing met het return van een pointer in een method:

[cpp]
const unsigned int SIZE = 3;

Uint8 *toAsc(unsigned char N) {
Uint8 *arr = new Uint[SIZE];
// ...
return arr;
}

Uint8 *asc = toAsc(N);
delete[] asc;
[/cpp]


Alleen moet je er dan dus wel zoals ik al zei rekening mee houden dat je het geheugen later weer moet vrijgeven. Maar er zijn ook heel veel oplossingen denkbaar waarbij je geen dynamisch geheugen hoeft te gebruiken hoor:

[cpp]
void toAsc(unsigned char *arr, unsigned char N) {
// ...
}

unsigned char arr[SIZE] = {0};
toAsc(arr, N); // arr zit in dit voorbeeld al binnen de scope van de aanroepende method en die pointer geeft die geheugenruimte dus door aan de method toAsc. Belangrijk is wel om je te realiserenn dat het in dit geval zo kan
// doordat de grootte buitenaf al is gespecificeerd en dat je de grootte van een pointer niet binnen de aanroepende method kunt bepalen (de grootte zal dan namelijk gewoon de grootte van het geheugenadres zijn (32 of 64 bits).
// In plaats van een pointer kun je vaak ook gewoon een & voor de variabele zetten en dan wordt het geheugenadres van de variabele doorgegeven.



Verder kun je dus geen pointers teruggeven die alleen binnen de scope van die method een context hebben, maar zou je bijvoorbeeld wel een eigen datatype kunnen maken met een array van chars, gezien je op die manier ook
een array kunt teruggeven:

typedef struct _pack {
unsigned char val[SIZE];
} pack;


pack toAsc(unsigned char N) {
pack p;
// ...
return p;
}



pack asc = toAsc(N);


Maar je zou bijvoorbeeld ook een std::string kunnen gebruiken met een vaste lengte:

std::string toAsc(unsigned char N) {
std::string asc = std::string('?', SIZE);
// ..
return asc;
}

En zo zijn de mogelijkheden die je verder nog kunt bedenken vrijwel oneindig, maar indien je zo min mogelijk overhead wilt hou je een stuk minder mogelijkheden over.
[/cpp]

Na al die halve stukjes ook maar een volledige implementatie:


[cpp]
void toAsc(unsigned char *arr, unsigned int N) {
for (unsigned int idx = 0, div = 100, temp; idx < SIZE; ++idx) {
temp = val / div;
arr[idx] = temp + 0x32;
val -= temp * div;
div /= 10;
}
}

// ...

unsigned char arr[SIZE] = {0};
toAsc(&arr, 120);
[/cpp]
 
lol, die 0x32 is uiteraard niet correct en moet 0x30 zijn. :$
 
Hallo CoD_NL,

Bedankt voor je reactie. Het eerste klopt idd voor mij, moet de array buiten de scope aanmaken.
Alleen werk ik met C en niet met CPP en kan dus niet dynamisch variabelen aanmaken. De enige mogenlijkheid is dus om met pointers te verwijzen naar de reeds aangemaakte array om hem te bewerken. Ik hoef dan niet eens een returnvalue te hebben.

Code:
Uint8 ASCII[5];


void Berwerken(UInt8 *Ptr)
{
    //Handeling
}

Functiecall:

Code:
Berwerking(&ASCII[0]);

De wijzigingen die "Berwerkingen" uitvoert zijn nu permanent gedaan.
Dit klopt toch?

Groeten
 
Ongeloofelijk, 3x Bewerking verkeerd getypt:(.

De functie heet dus Bewerking
 
In C is dat ook gewoon mogelijk hoor, alleen niet onder de namen new/delete maar malloc/free.

[cpp]
uint8_t *arr = malloc(SIZE * sizeof(uint8_t));
// ...
free(arr);
[/cpp]
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan