» »

[C] predprocesor

[C] predprocesor

slovencl ::

Rad bi naredil nekaj takega:

#define a 100000
#define b (a/3)

#if ((b < 0x000000ff) || (b > 0xffffffff))
#error b out of range, b=??
#endif

Pri čemer bi rad, da mi v errorju izpiše vrednost b-ja. kako se to naredi?
Zanima me še, koko lahko v predprocesorju določim spremenljivke (float intiger itd) - ali bo b v mojem primeru zaokrožil na integer?
  • spremenilo: snow ()

Gundolf ::

Ti bi kar s preprocesorjem programiral? A lahko poveš, kaj si želiš deseči na ta način? Ker verjetno obstaja druga pot, na katero nisi pomislil.

Preprocesor ti le spremeni source file. Nič ti ne izračuna. Tvoj program torej prepiše takole:

#define a 100000
#define b (100000/3)

#if (((100000/3) < 0x000000ff) || ((100000/3) > 0xffffffff))
#error (100000/3) out of range, (100000/3)=??
#endif

Šele ko en makro (a in b sta makra, ne spremenljivki!) kje uporabiš, se njegova vrednost izračuna. Po moje ti #if ne bo delal prav. V #errorju pa tudi lahko le izpišeš string, ne moreš pa tudi 'vrednosti' makrojev. Glede tipov spremenljivk: makri niso spremenljivke. Tip številke pa lahko določiš tako:
10000 //int
10000.0 // double
10000.0f // float

SasoS ::

zakaj bi to delal s predprocesorjem?

slovencl ::

Zato, ker imaš v mikrokontrolerjih možne določene nastavitve, ki pa jih hardver ne podpira več, zato jih je potrebno preprečit.

Zgodovina sprememb…

  • spremenil: slovencl ()

Gundolf ::

Dej povej, kaj točno želiš narest. Ker se mi zdi da predprocesor ni najboljša izbira za to (karkoli že to je :)). Preprocesor moraš vedno mešat z navadnim programom. To pri tebi manjka.

slovencl ::

#define a 100000
#define b (a/3)

#if ((b < 0x000000ff) || (b > 0xffffffff))
#error b out of range, b=??
#endif

void init_čip()
{
register=b; // zapiše vrednost v register
}

To je vse. Bistvo teh makrotov je, da tebi ni treba vsakič posebej študirat datasheet od čipa. Npr. če hočem da čip deluje pri neki frekvenci, se to izračuna iz nekaj enačb, pri čemer pa morajo biti izpolnjeni določeni pogoji.

Zgodovina sprememb…

  • spremenil: slovencl ()

Gundolf ::

No po mojem mnenju si izbral najslabši možen način za tole. Sploh ne vidim razloga za uporabo preprocesorja. Recimo tudi, da v tvoji kodi nimaš takih imen za makroje (a in b), če pa jih slučano imaš, vedi da je to skrajno nevarna zadeva. A bi bilo kaj narobe s tako kodo:
static const init_chip_default_freq = 100000;

void init_čip(int freq = init_chip_default_freq) {
   freqInitializer = freq / 3;
   if ((freqInitializer >= 0x000000ff) && (freqInitializer <= 0xffffffff))
       register = freqInitializer ; // zapiše vrednost v register
   else
      ...
}

kjer ... zamenjaš s primerno zadevo. Če uporabljaš C++ je to recimo throw, drugače pa je lahko kakšen output o napaki, samo return iz funkcije s kakšno error-vrednostjo ipd. Drugače če uporabljaš C++, obstajajo načini tole tudi compile-time pogledat.

Zgodovina sprememb…

  • spremenil: Gundolf ()

snow ::

> Preprocesor ti le spremeni source file.

Ravno to je tipična uporaba preprocesorja pri programiranju mikroprocesorjev (PIC,AVR,LPC...).
Imaš določene knjižnice, kjer spremeniš samo par definov in dobiti nov source, ki dela z novimi nastavitvami/hardwarom.

Recimo tipična uporaba takšnih definov je pri uporabi delay funkcij, kjer samo določih frekvenco s katero deluje mikrokontroler in nato so vse DelayUs, DelayMs itd. funkcije ok.

Upam, da sem kaj razjasnil.

Avtorja teme pa naprošam, da poda dejanski primer, pri katerem bi želel uporabo preprocesorja.
Random mutation plus nonrandom cumulative natural selection - Richard Dawkins

slovencl ::

Tako kot je rekel snow, to more naredit predprocesor, ne pa da s tem računanjem dodatno zasedam prostor na čipu.

Primer z a in b je samo primer, ker sem hotel izpostavit problem, ne pa vsega okoli. Tukaj je pa pravi primer:

#define PCLK 25000000
#define WTD_TIME_PERIOD 1000
#define WDT_FEED_VALUE (WTD_TIME_PERIOD*PCLK/4000000)

#if ((WDT_FEED_VALUE < 0x000000ff) || (WDT_FEED_VALUE > 0xffffffff))
#error WTD_TIME_PERIOD out of range [WDT_FEED_VALUE]
#error correct WTD_TIME_PERIOD and recompile
#endif

Zdej bi pa rad, da mi v error izpiše koliko je dejansko [WDT_FEED_VALUE], ker sedaj tud preverit ne morem kaj je dejansko izračunal, in zaradi tega tudi ne morem ugotovit kaj je napaka.

Poleg tega mi za velike vrednosti WTD_TIME_PERIOD pri prevajanju v kodi javi opozorilo "warning: integer overflow in expression"
"
void WDTInit( void )
{
WDTC = WDT_FEED_VALUE; // tukaj je napaka
}

WDTC je 32 bitni register, tako da je zgleda WTD_TIME_PERIOD večji od območja uint32.

Vsemu temu bi se rad izognil, zato tudi sprašujem kot kaj predprocesor privzame vrednosti pri računanju, kot int, kot float?

Gundolf ::

Aha, razumem, na čipu šparaš prostor.

Potem delaš kot je treba, samo #error ti pa nikoli ne more vrniti izračunanega. Vsaj kolikor je meni znano ne. Obstaja način, kako parameter vnešen v makro spremeniš v string,samo ne vem, kako #error reagira an stringe. Lahko pa probaš:
#error WTD_TIME_PERIOD out of range #WDT_FEED_VALUE
Finta je v tistem # pred imenom parametra.

Edit: sem se spomnl da tole deluje le v makroju, tako da zna biti da sploh en bo nič.

Zgodovina sprememb…

  • spremenil: Gundolf ()

snow ::

> Poleg tega mi za velike vrednosti WTD_TIME_PERIOD pri prevajanju v kodi javi opozorilo "warning: integer overflow in expression"

Za številkami dodaj ULL. Gre za long long (64 bitna) števila. Sicer končni rezultat mora biti 32 biten, vmes pa so lahko večje cifre.
Random mutation plus nonrandom cumulative natural selection - Richard Dawkins

ježek ::

Cjev preprocesor je na nekaterih področjih nekoliko _trotel_. Sam si pri izpisih takšnih zadev pomagam z #line, vendar z tem ne moreš izpisovati makrotov, ampak le konstante! Tvoj primer:
#line PLCK "Vrednost PLCK je"
#error kar ni tako vredu

Vendar je uporaba tega zelo omejena.

Malenkost bolj uporaben je ta način: Namesto #error blabla daš preprosto WDT_FEED_VALUE, nato pa kompajlaš z direktivo -E . V konzolo se ti bo izpisala vrednost tega makrota (sicer čisto na koncu in hkrati bo to povzročilo error, ampak saj že tako ali tako prej skočiš ven iz kompajlanja z #error). Ne vem na katerih kompajlerjih vse deluje -E (na gcc sigurno). Ampak vsekakor si še poglej man stran od tvojega prevajalnika!, saj ima ponavadi cel kup uporabnih direktiv ;)


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[C] parse error

Oddelek: Programiranje
111015 (950) ql000
»

[C/C++] Variadic Macros

Oddelek: Programiranje
122095 (1920) OwcA
»

X server in Nvidia na FC#

Oddelek: Operacijski sistemi
271933 (1760) HellRaiseR
»

[visual c++] #ifdef _DEBUG

Oddelek: Programiranje
51090 (1031) Vesoljc
»

xserver-xree86

Oddelek: Operacijski sistemi
61449 (1361) Skrat

Več podobnih tem