/ 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
structs og makroer
Fra : Klaus Petersen


Dato : 19-05-04 11:53

Hej ng.

Jeg kan virkelig ikke se fejlen i denne her makro:

struct RGBColor
{
unsigned char r;
unsigned char g;
unsigned char b;
};

private:
RGBColor _palette [16];

// makrodefinationen
#define RGBCol(index,r,g,b) this->_palette [index].r = r;

// Og makrokaldet er:

RGBCol ( 0, 0, 0, 0 );

Fejlen den giver mig er:

"error C2143: syntax error : missing ';' before 'constant'"
og
"error C2106: '=' : left operand must be l-value"

.... i linjen med makrokaldet.

Hvad er der galt?

Klaus.



 
 
Bertel Brander (19-05-2004)
Kommentar
Fra : Bertel Brander


Dato : 19-05-04 18:57

Klaus Petersen wrote:
> Hej ng.
>
> Jeg kan virkelig ikke se fejlen i denne her makro:
>
> struct RGBColor
> {
> unsigned char r;
> unsigned char g;
> unsigned char b;
> };
>
> private:
> RGBColor _palette [16];
>
> // makrodefinationen
> #define RGBCol(index,r,g,b) this->_palette [index].r = r;

Problemet er at du har to ting der hedder r, RGBColor::r og
macro parametren r, omdøb en af dem, f.ex:

#define RGBCol(index_,r_,g_,b_) this->_palette [index_].r = r_;

Et andet problem er at du får et ; for meget, det til slut på
macro'en og det i kaldet.
Man kunne lave det som:

#define RGBCol(index, r_, g_, b_)\
do { \
this->_palette [index].r = r_; \
this->_palette [index].g = g_; \
this->_palette [index].b = b_; \
}while(0)

Herved vil blokken fremså som et statement, dvs det vil virke selv med:

if(Do())
RGBCol(1,2,3,4);

Man kunne også mene at man burde lave det som en funktion

/b

Klaus Petersen (19-05-2004)
Kommentar
Fra : Klaus Petersen


Dato : 19-05-04 21:10

> Problemet er at du har to ting der hedder r, RGBColor::r og
> macro parametren r, omdøb en af dem, f.ex:
>
> #define RGBCol(index_,r_,g_,b_) this->_palette [index_].r = r_;

Hm, ja det har du ret i - ændrer jeg f.eks. r til red, compiler det fint.

Det kommer dog noget bag på mig, at det var et problem. Jeg har opfattet
makroer, som en slags inline procedure.

Men den kopierer jo åbenbart bare koden ind og naivt erstatter alle
identifiers med samme navn som een af paramtrerne uden at tage scope i
betragtning.

> Et andet problem er at du får et ; for meget, det til slut på
> macro'en og det i kaldet.

Jeg forstår ikke helt hvorfor du benævner det som et problem. Det er vel
bare en tom (no-op) sætning...

> Man kunne lave det som:
>
> #define RGBCol(index, r_, g_, b_)\
> do { \
> this->_palette [index].r = r_; \
> this->_palette [index].g = g_; \
> this->_palette [index].b = b_; \
> }while(0)
>
> Herved vil blokken fremså som et statement, dvs det vil virke selv med:
>
> if(Do())
> RGBCol(1,2,3,4);
>
> Man kunne også mene at man burde lave det som en funktion

I hver fald mange tak for hjælpen



Bertel Brander (19-05-2004)
Kommentar
Fra : Bertel Brander


Dato : 19-05-04 21:50

Klaus Petersen wrote:
>>Problemet er at du har to ting der hedder r, RGBColor::r og
>>macro parametren r, omdøb en af dem, f.ex:
>>
>>#define RGBCol(index_,r_,g_,b_) this->_palette [index_].r = r_;
>
>
> Hm, ja det har du ret i - ændrer jeg f.eks. r til red, compiler det fint.
>
> Det kommer dog noget bag på mig, at det var et problem. Jeg har opfattet
> makroer, som en slags inline procedure.
>
> Men den kopierer jo åbenbart bare koden ind og naivt erstatter alle
> identifiers med samme navn som een af paramtrerne uden at tage scope i
> betragtning.
>

Med din oprindelige macro:
#define RGBCol(index,r,g,b) this->_palette [index].r = r;

Bliver:

RGBCol ( 0, 0, 0, 0 );


Oversat til
this->_palette[0].0 = 0;;

Hvilket ikke kan kompilere. Du har ret i at preprocessoren ikke
kender til scope, den kender intet til syntax, og kunne
(næsten og med få forbehold) bruges til at preprocesse f.ex.
pascal og lisp.

>>Et andet problem er at du får et ; for meget, det til slut på
>>macro'en og det i kaldet.
>
>
> Jeg forstår ikke helt hvorfor du benævner det som et problem. Det er vel
> bare en tom (no-op) sætning...
>
>

De to ;; til slut er ikke et problem med mindre du bruger den som:

if(DoIt())
RGBCol(0,0,0,0);
else
RGBCol(0,0xff, 0xff, 0xff);

Normalt bør man forsøge at få macroer der ligner functioner til at
opføre sig som funktioner.

/b

Bertel Lund Hansen (19-05-2004)
Kommentar
Fra : Bertel Lund Hansen


Dato : 19-05-04 21:48

Klaus Petersen skrev:

>Men den kopierer jo åbenbart bare koden ind og naivt erstatter alle
>identifiers med samme navn som een af paramtrerne uden at tage scope i
>betragtning.

Tænk på en makro på samme måde som et tekstbehandlingsprograms
søg-og-erstat.

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

Byrial Jensen (19-05-2004)
Kommentar
Fra : Byrial Jensen


Dato : 19-05-04 21:53

Klaus Petersen skrev:
> Det kommer dog noget bag på mig, at det var et problem. Jeg har opfattet
> makroer, som en slags inline procedure.
>
> Men den kopierer jo åbenbart bare koden ind og naivt erstatter alle
> identifiers med samme navn som een af paramtrerne uden at tage scope i
> betragtning.

Sådan er det. Makroer ekspanderes i princippet (men sjældent i praksis)
af en selvstændig præprocessor som kun laver en rent leksikal analyse.

>>Et andet problem er at du får et ; for meget, det til slut på
>>macro'en og det i kaldet.
>
> Jeg forstår ikke helt hvorfor du benævner det som et problem. Det er vel
> bare en tom (no-op) sætning...

Det er et problem i konstruktioner som for eksempel

if (condition)
RGBCol(1,2,3,4);
else
RGBCol(5,6,7,8);

hvor der kommer en syntaksfejl idet der er 2 sætninger mellem "if" og
"else".

Per Abrahamsen (20-05-2004)
Kommentar
Fra : Per Abrahamsen


Dato : 20-05-04 13:55

"Klaus Petersen" <spectual2@getTOnet.dk> writes:

> Det kommer dog noget bag på mig, at det var et problem. Jeg har opfattet
> makroer, som en slags inline procedure.

Det er de ikke. Men hvorfor ikke bare definere RGBCol som en rigtig
inline funktion?

struct Foo
{
struct RGBColor
{
unsigned char r;
unsigned char g;
unsigned char b;
};
private:
RGBColor _palette [16];
public:
inline void RGBCol (int index, char r, char g, char b)
{_palette [index].r = r; }
};

Lasse Westh-Nielsen (20-05-2004)
Kommentar
Fra : Lasse Westh-Nielsen


Dato : 20-05-04 16:54

"Per Abrahamsen" <abraham@dina.kvl.dk>:
> "Klaus Petersen" <spectual2@getTOnet.dk> writes:

> > Jeg har opfattet makroer, som en slags inline procedure.

> Det er de ikke.

Men hvad er de så? Eller rettere, er der nogen gode grunde til at bruge
#define til andet end at administrere #include-hierarkier?

Jeg bruger sjældent selv #define til andet end header-guards, alle and
konstruktioner jeg kan komme på (til definition af konstanter, makroer) kan
lige så godt skrives som rigtige konstanter eller funktioner.

Er der nogle fordele ved #define som jeg ikke er opmærksom på?

- Lasse


--
Lasse Westh-Nielsen
lasse@daimi.au.dk




Kent Friis (20-05-2004)
Kommentar
Fra : Kent Friis


Dato : 20-05-04 18:09

Den Thu, 20 May 2004 17:53:32 +0200 skrev Lasse Westh-Nielsen:
> "Per Abrahamsen" <abraham@dina.kvl.dk>:
>> "Klaus Petersen" <spectual2@getTOnet.dk> writes:
>
>> > Jeg har opfattet makroer, som en slags inline procedure.
>
>> Det er de ikke.
>
> Men hvad er de så?

Søg og erstat.

> Eller rettere, er der nogen gode grunde til at bruge
> #define til andet end at administrere #include-hierarkier?

Normalt ikke.

> Jeg bruger sjældent selv #define til andet end header-guards, alle and
> konstruktioner jeg kan komme på (til definition af konstanter, makroer) kan
> lige så godt skrives som rigtige konstanter eller funktioner.
>
> Er der nogle fordele ved #define som jeg ikke er opmærksom på?

Kun hvis man er til obfuscated C, eller foretrækker Pascal...

#define begin {
#define end }
#define procedure void



Mvh
Kent
--
Help test this great MMORPG game - http://www.eternal-lands.com/

Jonas Meyer (23-05-2004)
Kommentar
Fra : Jonas Meyer


Dato : 23-05-04 08:39

Lasse Westh-Nielsen wrote:
> Er der nogle fordele ved #define som jeg ikke er opmærksom på?

Der findes nogen tilfælde, hvor de kan gøre livet lidt lettere -
Det er altsammen kun med et formål - at slippe for at skrive.

#define FAIL() { std::cout << "program failed at" << __FILE__ << ":" <<
__LINE__ << std::endl; exit( EXIT_FAILURE ); }

eller tilsvarende til at kaste en exception. Det gør det muligt at finde
fejlen uden at sætte gang i debuggeren. Jeg skal nok lige bemærke at
__LINE__ makroen så vidt jeg er klar over, ikke er en del af standarden.
Den findes dog både i g++ og msvc, jeg ved ikke med andre.

En anden ting kunne være at registrere klasser i en factory, funktioner
til et scriptsprog og lignende, vha # og ## operatorene:

#include <string>
#include <iostream>
using namespace std;

class Interface{};
class Factory
{
public:
static bool register_( Interface* create(), string name )
{
cout << "registered " << (void*)(&create) << " with name " << name
<< endl;
return true;
}
};

#define REGISTER_CLASS( f ) \
Interface* create##f(){\
return new f;\
}\
bool discard##f = Factory::register_(create##f,#f)

class foo : public Interface
{
};

REGISTER_CLASS( foo );

Det har givetvis et par begrænsninger, men det er _rart_ at slippe for
en masse skriverier.

Jeg kender ikke nogen måder at løse de to ovenstående problemer på, uden
makroerne(Vil gerne høre hvis jeg tager fejl) - Så lige præcis der er
_jeg_ glad for dem.

mvh Jonas

Kent Friis (23-05-2004)
Kommentar
Fra : Kent Friis


Dato : 23-05-04 08:57

Den Sun, 23 May 2004 09:38:44 +0200 skrev Jonas Meyer:
> Lasse Westh-Nielsen wrote:
>> Er der nogle fordele ved #define som jeg ikke er opmærksom på?
>
> Der findes nogen tilfælde, hvor de kan gøre livet lidt lettere -
> Det er altsammen kun med et formål - at slippe for at skrive.
>
> #define FAIL() { std::cout << "program failed at" << __FILE__ << ":" <<
> __LINE__ << std::endl; exit( EXIT_FAILURE ); }
>
> eller tilsvarende til at kaste en exception. Det gør det muligt at finde
> fejlen uden at sætte gang i debuggeren. Jeg skal nok lige bemærke at
> __LINE__ makroen så vidt jeg er klar over, ikke er en del af standarden.
> Den findes dog både i g++ og msvc, jeg ved ikke med andre.

r.16.10, side 614, The C++ programming language, second edition.

__LINE__

__FILE__

__DATE__

__TIME__

Mvh
Kent
--
Help test this great MMORPG game - http://www.eternal-lands.com/

Mogens Hansen (23-05-2004)
Kommentar
Fra : Mogens Hansen


Dato : 23-05-04 09:25


"Jonas Meyer" <a@b.c> wrote:

[8<8<8<]
> Jeg skal nok lige bemærke at
> __LINE__ makroen så vidt jeg er klar over, ikke er en del af standarden.

Jo, __LINE__ er en del af C++ standarden (§16.8), sammen med __FILE_,
__DATE__, __TIME__ og __cplusplus.

[8<8<8<]
> Jeg kender ikke nogen måder at løse de to ovenstående problemer på, uden
> makroerne(Vil gerne høre hvis jeg tager fejl)

Ensartet behandling af forskellige typer håndteres ofte let med templates.
F.eks. kan registering af en type i en factory klasse klares med templates

<C++ kode>
#include <iostream>

using namespace std;

class interface
{
protected:
virtual ~interface() {}
};

class factory
{
public:
template <typename T>
class reg_type
{
public:
reg_type()
{
interface* must_be_interface = static_cast<T*>(0);
cout << "Do whatever is needed to register the type" << endl;
}
};
};

class foo : public interface
{
};

factory::reg_type<foo> reg_foo;
</C++ kode>

Venlig hilsen

Mogens Hansen



Jonas Meyer (23-05-2004)
Kommentar
Fra : Jonas Meyer


Dato : 23-05-04 09:47

Mogens Hansen wrote:

> "Jonas Meyer" <a@b.c> wrote:
>
> [8<8<8<]
>
>>Jeg skal nok lige bemærke at
>>__LINE__ makroen så vidt jeg er klar over, ikke er en del af standarden.
>
>
> Jo, __LINE__ er en del af C++ standarden (§16.8), sammen med __FILE_,
> __DATE__, __TIME__ og __cplusplus.

Ja, jeg kan se I har ret - Jeg tror jeg blandede den sammen med
__FUNCTION__.


> Ensartet behandling af forskellige typer håndteres ofte let med templates.
> F.eks. kan registering af en type i en factory klasse klares med templates
>
> <C++ kode>
[klip]
> factory::reg_type<foo> reg_foo;
> </C++ kode>

Ja, det er en god løsning - Det eneste jeg savner er # operatoren til at
lave klassenavnet automatisk. Eller måske endnu bedre, et standardiseret
output fra typeid( T ).name().

mvh Jonas

Jesper Louis Anderse~ (20-05-2004)
Kommentar
Fra : Jesper Louis Anderse~


Dato : 20-05-04 18:39

Bertel Brander <bertel@post4.tele.dk> wrote:
>
> Man kunne ogs? mene at man burde lave det som en funktion

Nemlig!

Det er meget sandsynligt at compileren vil inline det anyway og
med stor sandsynlighed, saa vil et inline-direktiv goere det
endnu mere sandsynligt at skidtet bliver inlinet. Nu er det
jo C++ vi leger med.

Makroer skal kun benyttes, hvis det giver en fordel, og det
goer det meget sjaeldent i C++. C er en anden sag.

--
j.

Per Abrahamsen (21-05-2004)
Kommentar
Fra : Per Abrahamsen


Dato : 21-05-04 19:23

"Lasse Westh-Nielsen" <lasse@daimi.au.dk> writes:

> Men hvad er de så? Eller rettere, er der nogen gode grunde til at bruge
> #define til andet end at administrere #include-hierarkier?

Der er bred enighed om at man bør prøve at undgå dem, i hvert fald i C++.

I C bruges de mest til at implementere primitive og upålidelige
varianter af features, der er indbyggede i C++. Som for eksempel
templates. Jeg vil nok mene at det vil være smartere at skifte til C++,
end at genimplementere C++ i C's pre-processor.

Man kan nogen gange bruge det til at omgå defekte compilere. For
eksempel

#define for if (0) {} else for

hvis ens C++ compiler ikke håndterer for-scope korrekt. Igen, at
bruge en ikke-defekt C++ compiler er normalt at foretrække.

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

Månedens bedste
Årets bedste
Sidste års bedste