/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
problemer med define
Fra : holst


Dato : 13-05-02 14:40

Hej NG

Jeg har tre defines:

#define SYSCFG 0x03FF0000
#define INTPND (SYSCFG + 0x4004)
#define IRQPendAll 0x1fffff

senere i filen vil jeg gerne gøre flg:

INTPND = IRQPendAll;

Det brokker kompileren sig over med flg. fejlbesked:

Illegal in the context of an l-value: '+'

Er der nogen af Jer, som kan se hvad der er galt?

på forhånd tak.
holst



 
 
Bertel Lund Hansen (13-05-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 13-05-02 15:41

holst skrev:

>#define SYSCFG 0x03FF0000
>#define INTPND (SYSCFG + 0x4004)
>#define IRQPendAll 0x1fffff

>senere i filen vil jeg gerne gøre flg:

> INTPND = IRQPendAll;

Hæ.

>Illegal in the context of an l-value: '+'

#define som du bruger det her, svarer til Search-and-Replace. Det
er en ren tekstudskiftning der sker. Compileren skal altså
oversætte:

   (SYSCFG + 0x4004) = IRQPendAll;

Det kan den ikke.

--
Bertel
http://lundhansen.dk/bertel/   FIDUSO: http://fiduso.dk/

Bjarke Dahl Ebert (13-05-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 13-05-02 16:40

"Bertel Lund Hansen" <nospam@lundhansen.dk> wrote in message
news:91kvdu003s376qfi2u601lsr7eo88mqfof@news.telia.dk...

> holst skrev:
> > INTPND = IRQPendAll;
>
> Hæ.
> #define som du bruger det her, svarer til Search-and-Replace. Det
> er en ren tekstudskiftning der sker.

Jep. #define er det rene skrammel. Den er fx totalt scope-ignorant.
Hvis man laver "#define foo ..." kan man ikke NOGET sted i programmet have
en variabel, metode, eller noget som helst andet der hedder foo.

Der er sjældent en rigtig godt grund til at bruge preprocessoren. Man kan
næsten altid bruge andre sprog-features (specielt i C++), og man bør IMHO
også gøre det selvom det koster lidt ekstra clockcykler hist og her.
En eller anden klog mand (Knuth?) har også sagt "Premature optimization is
the root of all evil". Jeg kunne ikke være mere enig. Ikke mindst fordi folk
generelt ikke er ret gode til at gætte hvor man virkelig kan vinde noget
performance. (Mange "optimeringer" *koster* ligefrem performance).
Der er god grund til at starte med at skrive koden simpelt, og først når man
har bevis for at det kører for langsomt, håndoptimere det.

Den "ikke-optimerede" version af den nævnte kode er:

const unsigned long SYSCFG = 0x03FF0000;
const unsigned long INTPND = SYSCFG + 0x4004; /* Se - ingen parantes
nødvendig! */
const unsigned long IRQPendAll = 0x1fffff;

Det kan koste et par clockcykler ekstra pr. brug af konstanterne, da de
bliver kompileret til et memory-opslag i stedet for en immediate værdi i
instruktionen. Men det *HAR* vi altså som regel råd til.


Jeg har været ulykkeligt vidne til en headerfil med tre 50-liniers-makroer,
der gudhjælpemig definerede nogle klasse-templates! Gæt lige om det var
svært at finde rundt i, da der så var en fejl - compileren brokker sig jo
bare over den linie hvor makroen bruges, så må man selv gætte hvor i makroen
det er galt

Bjarke





Ivan Johansen (13-05-2002)
Kommentar
Fra : Ivan Johansen


Dato : 13-05-02 19:05

Bjarke Dahl Ebert wrote:

> Den "ikke-optimerede" version af den nævnte kode er:
>
> const unsigned long SYSCFG = 0x03FF0000;
> const unsigned long INTPND = SYSCFG + 0x4004; /* Se - ingen parantes
> nødvendig! */
> const unsigned long IRQPendAll = 0x1fffff;
>
> Det kan koste et par clockcykler ekstra pr. brug af konstanterne, da de
> bliver kompileret til et memory-opslag i stedet for en immediate værdi i
> instruktionen. Men det *HAR* vi altså som regel råd til.

Det er tilladt kompileren at sætte konstanter ind direkte i stedet for
at lægge dem i RAM. Da alle ordentlige kompilere gør dette, bliver
eksemplet med konstanter lige så optimalt som med defines, men langt
nemmere at foretage debugging på.

Ivan Johansen


Byrial Jensen (13-05-2002)
Kommentar
Fra : Byrial Jensen


Dato : 13-05-02 20:48

Bjarke Dahl Ebert <bebert@worldonline.dk> skrev:
> "Bertel Lund Hansen" <nospam@lundhansen.dk> wrote in message
> news:91kvdu003s376qfi2u601lsr7eo88mqfof@news.telia.dk...
>
>> holst skrev:
>> > INTPND = IRQPendAll;
>>
>> Hæ.
>> #define som du bruger det her, svarer til Search-and-Replace. Det
>> er en ren tekstudskiftning der sker.
>
> Jep. #define er det rene skrammel. Den er fx totalt scope-ignorant.
> Hvis man laver "#define foo ..." kan man ikke NOGET sted i programmet have
> en variabel, metode, eller noget som helst andet der hedder foo.

Det er forkert. En #define kan efter brug annulleres med en #undef.

> [Klip - diverse om "premature" optimeringer]

Det er ikke forkert, men det du skriver her har ikke noget med brug
af #defines at gøre.

> Den "ikke-optimerede" version af den nævnte kode er:
>
> const unsigned long SYSCFG = 0x03FF0000;
> const unsigned long INTPND = SYSCFG + 0x4004; /* Se - ingen parantes
> nødvendig! */
> const unsigned long IRQPendAll = 0x1fffff;

Hvordan det? Sætningen

INTPND = IRQPendAll;

vil da stadig give en oversætterfejl. I første tilfælde var det pga.
tildeling til et udtryk som ikke repræsenterede et objekt, og her
pga. tildeling til en const variabel.

Hvad er det egentlig du ønsker at sætningen skal gøre? Sig det, og
så kan vi diskutere hvordan du bedst definerer dine konstanter.

> Det kan koste et par clockcykler ekstra pr. brug af konstanterne, da de
> bliver kompileret til et memory-opslag i stedet for en immediate værdi i
> instruktionen. Men det *HAR* vi altså som regel råd til.

Så er det en dårlig oversætter du har! Fornuftige oversættere laver
samme objektkode uanset om du bruger defines eller const variable.

Richard Flamsholt (13-05-2002)
Kommentar
Fra : Richard Flamsholt


Dato : 13-05-02 23:39

Byrial Jensen <bjensen@nospam.dk> skrev:
>>> holst skrev:
>>> > INTPND = IRQPendAll;
>
>Hvad er det egentlig du ønsker at sætningen skal gøre?

Mon ikke holst roder med at skrive direkte til en hardcodet adresse? I
så fald skal han først fortælle hvilken datatype, der forventes at være
på den adresse, og derefter dereferere det udtryk. Altså:

   *(unsigned int*)INTPND = IRQPendAll; /* for 32bit integers */

I øvrigt: hvis const variable ellers var rigtige konstanter i C kunne
man ofte slippe for at bruge #define. Men det er de jo ikke (man kan fx
ikke skrive 'const int SIZE=1000; char buf[SIZE];').

--
Richard Flamsholt
richard@flamsholt.dk - www.richard.flamsholt.dk

Byrial Jensen (14-05-2002)
Kommentar
Fra : Byrial Jensen


Dato : 14-05-02 00:14

Richard Flamsholt <richard@flamsholt.dk> skrev:
> Mon ikke holst roder med at skrive direkte til en hardcodet adresse? I
> så fald skal han først fortælle hvilken datatype, der forventes at være
> på den adresse, og derefter dereferere det udtryk. Altså:
>
>    *(unsigned int*)INTPND = IRQPendAll; /* for 32bit integers */

Data på hårdkodede adresser vil typisk være volatile:

*(volatile uint32_t *)INTPND = IRQPendAll;

> I øvrigt: hvis const variable ellers var rigtige konstanter i C kunne
> man ofte slippe for at bruge #define. Men det er de jo ikke (man kan fx
> ikke skrive 'const int SIZE=1000; char buf[SIZE];').

Jo, det kan man godt i C99.

Bjarke Dahl Ebert (14-05-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 14-05-02 11:37

"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnae05vd.1ps.bjensen@ask.ask...
> Bjarke Dahl Ebert <bebert@worldonline.dk> skrev:
> > Jep. #define er det rene skrammel. Den er fx totalt scope-ignorant.
> > Hvis man laver "#define foo ..." kan man ikke NOGET sted i programmet
have
> > en variabel, metode, eller noget som helst andet der hedder foo.
> Det er forkert. En #define kan efter brug annulleres med en #undef.

Jojo, man kan have en slags lokal define. Men hvad er "efter brug"?
Header-filen kan jo ikke tillade sig at #undef'e en makro som det er
meningen at andre end den selv skal bruge.
Følgende dur ikke engang:
#define foo 42
#define bar (foo+1000)
#undef foo
const int a = bar; // <-- error - foo undefined

Og det ændrer heller ikke ved at makroer er totalt scope-ignorante, hvilket
er min egentlige anke.

> Hvad er det egentlig du ønsker at sætningen skal gøre? Sig det, og
> så kan vi diskutere hvordan du bedst definerer dine konstanter.

Det må du hellere spørge "holst" om .

> > Det kan koste et par clockcykler ekstra pr. brug af konstanterne, da de
> > bliver kompileret til et memory-opslag i stedet for en immediate værdi i
> > instruktionen. Men det *HAR* vi altså som regel råd til.
> Så er det en dårlig oversætter du har! Fornuftige oversættere laver
> samme objektkode uanset om du bruger defines eller const variable.

Så tror jeg at man skal erklære dem "static const long foo = 10;". Ellers
kan erklæringen jo kun stå i én translation unit (linkeren vil brokke sig
hvis en variabel er defineret (ikke bare erklæret) i flere forskellige
compilation units).

Givet den måde C og C++ håndterer compilation units, linkning og headerfiler
på (som efter min mening er noget skrammel - det er et af de få steder hvor
jeg mener at C++ kunne lære af Java), så er den bedste metode IMHO:

----- foo.h -----
extern const long foo;

----- foo.cpp -----
const long foo = 42;


På den måde kan man også ændre konstanten uden at rekompilere hele verden



Bjarke






Byrial Jensen (14-05-2002)
Kommentar
Fra : Byrial Jensen


Dato : 14-05-02 16:25

Bjarke Dahl Ebert <bebert@worldonline.dk> skrev:
> "Byrial Jensen" <bjensen@nospam.dk> wrote in message
>> Bjarke Dahl Ebert <bebert@worldonline.dk> skrev:
>> > Jep. #define er det rene skrammel. Den er fx totalt scope-ignorant.
>> > Hvis man laver "#define foo ..." kan man ikke NOGET sted i programmet have
>> > en variabel, metode, eller noget som helst andet der hedder foo.
>> Det er forkert. En #define kan efter brug annulleres med en #undef.
>
> Jojo, man kan have en slags lokal define.

Ja, det er primært til brug lokalt inden for én funktion at #undef
kan være nyttig.

>> Fornuftige oversættere laver
>> samme objektkode uanset om du bruger defines eller const variable.

Her tænkte jeg igen på lokale variable. Globale variable kan ikke
optimeres væk. Men når der er tale om globale data som deles mellem
flere oversættelsesenheder, ser jeg ikke det helt store problem i at
en defines virkefelt varer oversættelsesenheden ud (hvis den ikke
undef'es). En global variabel eller enumeration varer lige så længe
og kan ikke engang annulleres som en define kan.

> Så tror jeg at man skal erklære dem "static const long foo = 10;". Ellers
> kan erklæringen jo kun stå i én translation unit (linkeren vil brokke sig
> hvis en variabel er defineret (ikke bare erklæret) i flere forskellige
> compilation units).
>
> Givet den måde C og C++ håndterer compilation units, linkning og headerfiler
> på (som efter min mening er noget skrammel - det er et af de få steder hvor
> jeg mener at C++ kunne lære af Java), så er den bedste metode IMHO:
>
> ----- foo.h -----
> extern const long foo;
>
> ----- foo.cpp -----
> const long foo = 42;
>
>
> På den måde kan man også ændre konstanten uden at rekompilere hele verden
>

Ja, det kan selvfølgelig være praktisk nok.

Hvis man kan nøjes med data som kan repræsenteres som en int (og leve
med at genoversætte alle filer som bruger foo når værdien ændres),
kan man også bruge:

/*----- foo.h -----*/
enum foo_konstant { foo = 42 };

Bjarke Dahl Ebert (14-05-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 14-05-02 17:59

"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnae2b5j.113.bjensen@ask.ask...

> optimeres væk. Men når der er tale om globale data som deles mellem
> flere oversættelsesenheder, ser jeg ikke det helt store problem i at
> en defines virkefelt varer oversættelsesenheden ud (hvis den ikke
> undef'es). En global variabel eller enumeration varer lige så længe
> og kan ikke engang annulleres som en define kan.

Ja, en global variabel har lige så stort scope - nemlig oversættelsesenheden
ud.

Og dog!

const int foo = 42;
....

void f(int foo) // Kan du se visse problemer med at definere ovenstående med
en #define?
{
// ...
}

Men nånej, sådan noget kunne man aldrig komme til ved en fejltagelse, vel?



Jeg var engang ude for netop sådan et #define problem:

Det var et program skrevet i Borland Builder, og jeg fik en linkerfejl -
noget i stil med "Unresolved external void TServerSocket::SetPortA(int)"
Og jeg fattede ikke en brik - for TServerSocket (en Borland-klasse)
erklærede sgu ikke nogen SetPortA metode.

Jeg var RET længe om at opdage at problemet var windows.h. Den includede
indirekte en eller anden fil, som havde "#define SetPort SetPortA", og
vupti - så var metoden TServerSocket::SetPort omdøbt til SetPortA - både i
erklæringen og i brugen af den - kun linkeren kunne ikke lide det nye navn,
da man naturligvis linker med Borland's runtime-library, som kender
funktionen under navnet SetPort.

Formålet med "#define SetPort SetPortA" var naturligvis at "redirecte" alle
kald til SetPort til den nyere funktion (eller hvad ved jeg) SetPortA. Som
bivirkning havde den desværre at omdøbe ALT hvad der bar samme navn - uanset
scope! Selvfølgelig skulle den kun "omdøbe" den globale SetPort, men fordi
preprocessoren er totalt ligeglad med scopes (her specielt klassescopes), så
fik jeg den uheldige bivirkning.

Der var to mulige løsninger: (1) #include <windows.h>, #undef SetPort (hvor
fedt er det?), (2) vise mere omhu med rækkefølgen af includes (men så får
jeg compilefejl, hvis jeg kalder TServerSocket::SetPort, da compileren tror
jeg kalder TServerSocket::SetPortA - hvor fedt er det?)

Bjarke





Mogens Hansen (15-05-2002)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-02 08:19


"Bjarke Dahl Ebert" <bebert@worldonline.dk> wrote

> Formålet med "#define SetPort SetPortA" var naturligvis at "redirecte"
alle
> kald til SetPort til den nyere funktion (eller hvad ved jeg) SetPortA.

SetPortA er til når man ikke anvender Unicode
SetPortW er til når man anvender Unicode
Preprocessor macroen SetPort er til at vælge den rigtige udgave, afhængigt
af om man anvender Unicode eller ej.

> Som
> bivirkning havde den desværre at omdøbe ALT hvad der bar samme navn -
uanset
> scope! Selvfølgelig skulle den kun "omdøbe" den globale SetPort, men fordi
> preprocessoren er totalt ligeglad med scopes (her specielt klassescopes),

> fik jeg den uheldige bivirkning.

Det groteske er at preprocesor makroen (i C++) uden nogen problemer kan
erstattes med små inline funktioner, der ikke giver bivirkninger og som ikke
giver noget overhead.
I dag står der (i winspool.h)

#ifdef UNICODE
#define SetPort SetPortW
#else
#define SetPort SetPortA
#endif // !UNICODE

Det kunne med fordel laves om til

#ifdef __cplusplus
#ifdef UNICODE
inline BOOL SetPort(
IN LPWSTR pName,
IN LPWSTR pPortName,
IN DWORD dwLevel,
IN LPBYTE pPortInfo)
{ return SetPortW(pName, pPortName, dwLevel, pPortInfo); }
#else
inline BOOL SetPort(
IN LPSTR pName,
IN LPSTR pPortName,
IN DWORD dwLevel,
IN LPBYTE pPortInfo)
{ return SetPortA(pName, pPortName, dwLevel, pPortInfo); }
#endif // !UNICODE
#else
#ifdef UNICODE
#define SetPort SetPortW
#else
#define SetPort SetPortA
#endif // !UNICODE
#endif // !__cplusplus

Hvis blot Windows header-filerne ville udnytte C++ som "en bedre C" ...

Venlig hilsen

Mogens Hansen



Thomas Lykkeberg (16-05-2002)
Kommentar
Fra : Thomas Lykkeberg


Dato : 16-05-02 06:40

On Mon, 13 May 2002 15:40:14 +0200, "holst" <holst@control.auc.dk>
wrote:

>Hej NG
>
>Jeg har tre defines:
>
>#define SYSCFG 0x03FF0000
>#define INTPND (SYSCFG + 0x4004)
>#define IRQPendAll 0x1fffff
>
>senere i filen vil jeg gerne gøre flg:
>
> INTPND = IRQPendAll;
>
>Det brokker kompileren sig over med flg. fejlbesked:
>
>Illegal in the context of an l-value: '+'
>
>Er der nogen af Jer, som kan se hvad der er galt?
>
>på forhånd tak.
>holst
>
Jeps

#define SYSCFG   ((volatile unsigned long *)0x03FF0000)
#define INTPND   (SYSCFG + 0x4004)
#define IRQPendAll   0x1FFFFF

.....

*INTPND = IRQPendAll;

.....

Så skulle det vist virke efter hensigten..

Man kan jo ikke tildele en konstant en ny værdi, men det var vel
heller ikke det du ville. ?

/Thomas

Bertel Lund Hansen (16-05-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 16-05-02 12:31

Thomas Lykkeberg skrev:

>#define SYSCFG   ((volatile unsigned long *)0x03FF0000)
>#define INTPND   (SYSCFG + 0x4004)
>#define IRQPendAll   0x1FFFFF

>*INTPND = IRQPendAll;
>Så skulle det vist virke efter hensigten..

Det bliver til:

   *(((volatile unsigned long *)0x03FF0000) + 0x4004) = 0x1FFFFF;

før kompileringen.

>Man kan jo ikke tildele en konstant en ny værdi, men det var vel
>heller ikke det du ville. ?

Det er som man tager det. Han troede at han havde defineret nogle variable.

--
Bertel
http://lundhansen.dk/bertel/   FIDUSO: http://fiduso.dk/

Bjarke Dahl Ebert (16-05-2002)
Kommentar
Fra : Bjarke Dahl Ebert


Dato : 16-05-02 13:32

"Thomas Lykkeberg" <thomas@in.dk> wrote in message
news:dch6eu4fq1mhjet3vf19mcr31du2dd936j@4ax.com...
On Mon, 13 May 2002 15:40:14 +0200, "holst" <holst@control.auc.dk>
wrote:

> #define SYSCFG ((volatile unsigned long *)0x03FF0000)
> #define INTPND (SYSCFG + 0x4004)
> #define IRQPendAll 0x1FFFFF

Har I ikke overset et lille problem: (SYSCFG + 0x4004)

Da SYSCFG nu (efter makro-ekspansion) evaluerer til noget af typen "volatile
unsigned long*", vil den fysiske adresse jo vokse med 0x4004*sizeof(unsigned
long).

Dvs. adressen vil højst sandsynligt blive 0x03FF0000+0x10010.

C er og bliver noget skrammel - en mellemting mellem assembler og højniveau,
som ikke kan bestemme sig for at være nogen af delene


Bjarke





Thomas Lykkeberg (16-05-2002)
Kommentar
Fra : Thomas Lykkeberg


Dato : 16-05-02 21:38

On Thu, 16 May 2002 14:32:26 +0200, "Bjarke Dahl Ebert"
<bebert@worldonline.dk> wrote:

>Har I ikke overset et lille problem: (SYSCFG + 0x4004)
>
>Da SYSCFG nu (efter makro-ekspansion) evaluerer til noget af typen "volatile
>unsigned long*", vil den fysiske adresse jo vokse med 0x4004*sizeof(unsigned
>long).
>
>Dvs. adressen vil højst sandsynligt blive 0x03FF0000+0x10010.
>
>C er og bliver noget skrammel - en mellemting mellem assembler og højniveau,
>som ikke kan bestemme sig for at være nogen af delene
Jo det er rigtigt... Det er derfor man skal holde tungen lige i munden
her.

C er skam et herligt "sprog", hvis du spørger mig. Det _er_ faktisk
meget lavniveau. Basic, Pascal og måske også C++ er nok nærmere det
man ville kalde for højniveau sprog.

/Thomas

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste