|
| 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.
| |
|
|