Toon posts:

[C] Onbepaald aantal argumenten naar functie

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo,

ik probeer voor een embedded system (PIC16 serie) een printf functie te schrijven. Nu kan de 'echte' printf een onbepaalt aantal argumenten nemen (naast de standaard const char * kan je zoals je zal weten een onbepaalt aantal argumenten met variabelen opgeven). Hoe ik dat zou moeten opschrijven is als volgt:

void printf(const char* string, ...) { /* Code */ }

Nu is de vraag dus: Hoe berijk ik de argumenten onder de punten. Ik heb wel gevonden dat ze op een stack zitten, daar zal ik ze af kunnen poppen, maar waar zit dat stack? Is dat het gewone hardware stack of wat? En hoe weet ik waar de argumenten beginnen / eindigen?

BVD

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
STDARGS.H is your friend. :)
(Of varargs.h, voor Visual studio)

Meer specifiek, de functies va_start, va_end en va_arg

[ Voor 33% gewijzigd door MrBucket op 27-03-2006 22:45 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 07:57
Die punten heten de ellipsis en daarmee declareer je een functie met een variable argument list. De argumenten kun je uitlezen met een aantal macro's uit de C-library die tegenwoordig gestandaardiseerd zijn in de header stdarg.h.

Als je Googlet op stdarg of variable argument list zijn legio voorbeelden te vinden; hier staat bijvoorbeeld een toelichting:
http://www.thinkage.ca/english/gcos/expl/c/incl/stdarg.html

[ Voor 9% gewijzigd door Soultaker op 27-03-2006 22:45 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 23-02 22:12

.oisyn

Moderator Devschuur®

Demotivational Speaker

MrBucket schreef op maandag 27 maart 2006 @ 22:42:
STDARGS.H is your friend. :)
(Of varargs.h, voor Visual studio)
Bliep, stdargs.h is de ISO C manier, varargs.h is de Unix System V manier. Visual Studio gebruikt dus die eerste, maar ondersteunt die laatste ook voor compatibiliteit. stdargs.h is dus aan te raden :).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • igmar
  • Registratie: April 2000
  • Laatst online: 23-02 20:52

igmar

ISO20022

Verwijderd schreef op maandag 27 maart 2006 @ 22:25:

void printf(const char* string, ...) { /* Code */ }

Nu is de vraag dus: Hoe berijk ik de argumenten onder de punten. Ik heb wel gevonden dat ze op een stack zitten, daar zal ik ze af kunnen poppen, maar waar zit dat stack? Is dat het gewone hardware stack of wat? En hoe weet ik waar de argumenten beginnen / eindigen?
va_start, va_end en va_arg zijn de macro's die dat afhandelen. Het aantal argumenten weet je niet : die is afhankelijk van de formatstring, en die moet je dus gebruiken om te bepalen hoevaak je va_arg moet gebruiken.

Verwijderd

Topicstarter
Oke bedankt, zo ga ik er wel uitkomen :)

Verwijderd

Staan er in die header stdargs.h alleen die macro definities of ook andere functies? Ik wil namelijk ook zo'n print functie schrijven voor mijn eigen kernel. Ik kan echter nergens vinden hoe die macros zijn geimplementeerd.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 23-02 22:12

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik kan echter nergens vinden hoe die macros zijn geimplementeerd.
Je kunt toch gewoon je stdarg.h openen? Ze zijn iig compiler-specifiek, en dat is de reden waarom er geen generieke implementatie is. Maar op het x86 platform is het vrij simpel: de argumenten van een functie worden van achter naar voor op de stack gepushed. Als je dus het adres van het eerste argument weet (in het geval van printf dus de formatstring variabele) kun je het adres van de volgende uitrekenen mbv de sizeof operator.

Ook moet je eraan denken dat er in veelvouden van 4 bytes wordt gewerkt; structures van resp. 3 en 6 bytes nemen 4 en 8 bytes op de stack in (maar dit is dus in principe compiler specifiek!). Verder moet je er rekening mee houden dat de C/C++ standaard zegt dat voor vararg functies chars en shorts worden gepassed als int, en floats als doubles (wat ook de reden is dat er geen verschil is tussen floats en doubles voor printf).

[ Voor 8% gewijzigd door .oisyn op 28-03-2006 14:57 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-02 21:53
ik probeer voor een embedded system (PIC16 serie) een printf functie te schrijven
Ken et niet zo goed maar het is maar de vraag of de compiler dit ondersteunt. En als het ding het wel ondersteund mag je aannemen dat het behoorlijk wat code/stackruimte vraagt, iets wat in een dergelijk systeem vaak schaars voorhanden is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 07:57
@farlane: waarom kost het meer stackruimte dan een functie die 'gewoon' meerdere argumenten accepteert? En waarom zou het veel coderuimte kosten; die macro's zijn ongeveer zo gedefinieerd:
C:
1
2
3
#define va_start(ap,v) (ap = &v + sizeof(v))
#define va_arg(ap,t) (ap += sizeof(t), *(ap - sizeof(t)))
#define va_end(ap) (ap = 0)

Dus je kunt je wel voorstellen dat de code die die macro's genereren heel erg meevalt. (In de praktijk zitten er nog wat hacks in om de groottes van types goed in te schatten; een char wordt op de stack meestal geresized naar een int bijvoorbeeld, waardoor je niet sizeof(char) kunt gebruiken, maar dit zijn allemaal dingen die at compile time gebeuren en niet at runtime.)

Je kunt ze dus desnoods zelf definiëren, mist je compiler zo'n stackframe hanteert. (Deze methode werkt natuulijk niet als je argumenten in registers gaat passen, zoals bijvoorbeeld bij een fastcall conventie.)

In het uiterste geval kun je gewoon een printf() functie met een zinnig aantal argumenten definiëren (zeg, maximaal 20 ofzoiets) en die dan in een array stoppen:
C:
1
2
3
4
5
int printf(char *format, int a1, int a2, int a3, int a4)
{
   int args[4] = { a1, a2, a3, a4 };
   // printf-implementatie hier.
}

Als je dan een double wil printen moet je dan twee opvolgende ints casten (*(double*)(args + offset) ofzoiets). Natuurlijk is dit allemaal hardstikke platform-afhankelijk, maar ja, anders moet je ook maar gewoon stdarg.h gebruiken. ;)

[ Voor 37% gewijzigd door Soultaker op 29-03-2006 15:39 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-02 21:53
Soultaker schreef op woensdag 29 maart 2006 @ 15:36:
@farlane: waarom kost het meer stackruimte dan een functie die 'gewoon' meerdere argumenten accepteert? En waarom zou het veel coderuimte kosten; die macro's zijn ongeveer zo gedefinieerd:
Natuurlijk is dit allemaal hardstikke platform-afhankelijk, maar ja, anders moet je ook maar gewoon stdarg.h gebruiken. ;)
komt misschien meer door de implementatie van een gemiddelde printf functie, maar bijvoorbeeld in een AVR kost de printf van WinAVR je ongeveer 2k codegeheugen, stack laat ik ff in het midden ( 25% van wat je beschikbaar hebt op een gem AVR )

Ik kan me herinneren dat een PIC16 256 bytes RAM heeft ( zou ook nog wel eens 128 kunnen zijn ) waar je variabelen en je stack in moeten, dus je kunt je voorstellen dat elke byte RAM die je gebruikt er eigenlijk 0.5 teveel is.

Een printf met 20 parameters is op zo een systeem denk ik dan ook niet een zinnig aantal :)

[ Voor 5% gewijzigd door farlane op 29-03-2006 16:07 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Topicstarter
farlane, stdarg.h wordt door mijn compiler ondrsteunt :)
coderuimte zal het probleem niet zijn, data ruimte... tja, het is zoals je al zij niet de bedoeling 20 argumenten mee te gaan geven.
Deze PIC (PIC16LF876) heeft trouwens 384 byte RAM, het is dan ook wel een uit het topsegment van de PIC16 serie :9

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23-02 21:53
Tis alweer een tijd geleden dat ik wat met die dingen heb gedaan, dus het zou goed kunnen. De versie MPLAB waarmee ik heb gewerkt was volgens mij ontwikkeld voor Windows 3.11 , en die kan het absoluut niet :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1