Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2014-09

Hack for C-like macro functions — will it work in future?

8 messages · 7 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Роман

As we all know, C preprocessor allows function-like macros, including ones with empty expansion. They can be very convenient for things that you'll want to disable depending on conditional defines, such as logging or assertions.

#ifdef DEBUG
#define dprf(...) print_debug_message(__VA_ARGS__) #else
#define dprf(...)
#endif

I have a temptation to use this in FPC too. Here's a trick:

{$macro on}
{$ifdef DEBUG}
     {$define Log := ActualLog}
{$else}
     {$define Log := ;//}
{$endif}
if A then
   Log('will work until followed by ELSE at all or any statements on the
same line (because of ; and //, respectively).');
if B then
   Log('And should not be carried over to the next line, of course!');

Because constant {$ifdef DEBUG} ActualLog(...); {$endif} are rather cumbersome.

This is by design? Can I rely on this behavior in the future? ._.

Reply by email

Tomas Hajny
to Роман

On Wed, September 24, 2014 02:59, Роман wrote: .
.

Show quoted text 17 lines
{$macro on} {$ifdef DEBUG} {$define Log := ActualLog} {$else} {$define Log := ;//} {$endif} if A then Log('will work until followed by ELSE at all or any statements on the same line (because of ; and //, respectively).'); if B then Log('And should not be carried over to the next line, of course!'); Because constant {$ifdef DEBUG} ActualLog(...); {$endif} are rather cumbersome. This is by design? Can I rely on this behavior in the future? ._.

I assume that this should keep working in the future as well.

However, the trunk compiler offers also another option, although it may or may not be usable for you. In particular, take the following:

---------
var
 S2: string;
procedure Log (S: string);
begin
 {$IFDEF TEST}
  WriteLn (S);
 {$ENDIF TEST}
end;
begin
 ReadLn (S2);
 Log ('Input = ' + S2);
end.
=========

If this is compiled with trunk compiler using -OoREMOVEEMPTYPROCS (without -dTEST), procedure Log is not called at all and the concatenation of strings in its parameter is skipped as well.

As you can see, this solution shares the benefit of your macro approach, i.e. it doesn't suffer from IFDEF pollution either. At the same time, it is much safer and supports also more complex scenarios (multi-line strings and no restrictions on where Log may be called in the program flow).

There are two caveats (at least with the version I tried - about 2 months old):

1) The call isn't removed if the (conditionally) empty procedure is declared in another unit _unless_ you use -O4 (which includes also some other optimizations which may not be safe for your use). There might be another -Oo... option which allows to use this without enabling all uncertain optimizations, but I don't know whether such an option exists and which one it would be.

2) Interestingly, there is still some code generated for the empty procedure (and also included in the final executable). The size of this code is negligible, but it's there.

Tomas

Reply by email

Sven Barth
to Tomas Hajny
"Tomas Hajny" wrote 23 lines
However, the trunk compiler offers also another option, although it may or may not be usable for you. In particular, take the following: --------- var S2: string; procedure Log (S: string); begin {$IFDEF TEST} WriteLn (S); {$ENDIF TEST} end; begin ReadLn (S2); Log ('Input = ' + S2); end. ========= If this is compiled with trunk compiler using -OoREMOVEEMPTYPROCS (without -dTEST), procedure Log is not called at all and the concatenation of strings in its parameter is skipped as well.

Another possibility would be to define Log() as "inline", which should get rid of the call and maybe the concatenation as well and already works in 2.6.x (though "array of const" would not be supported if needed)

Regards,
Sven

Reply by email

Constantine Yannakopoulos
to Sven Barth
Sven Barth wrote 31 lines
Am 24.09.2014 10:15 schrieb "Tomas Hajny" : > However, the trunk compiler offers also another option, although it may or > may not be usable for you. In particular, take the following: > > --------- > var > S2: string; > > procedure Log (S: string); > begin > {$IFDEF TEST} > WriteLn (S); > {$ENDIF TEST} > end; > > begin > ReadLn (S2); > Log ('Input = ' + S2); > end. > ========= > > If this is compiled with trunk compiler using -OoREMOVEEMPTYPROCS (without > -dTEST), procedure Log is not called at all and the concatenation of > strings in its parameter is skipped as well. Another possibility would be to define Log() as "inline", which should get rid of the call and maybe the concatenation as well and already works in 2.6.x (though "array of const" would not be supported if needed)

Another technique​ I have used in Delphi and works in fpc as well is using the Assert() procedure with a function that has side-effects as argument. E.g.:

function Log(const S: string): Boolean; inline;
begin
  WriteLn(S);
  Result := True;
end;
begin
  Assert(Log('Hello'),  '');
​end;​

​When the program is compiled with assertions enabled it will output a "Hello". ​​When it is compiled with assertions disabled the call to DoWrite and possibly DoWrite itself will be omitted from the exe by the compiler. No IFDEFs and no macros necessary.

--Constantine

Reply by email

Philippe
to Sven Barth: Another possibility would be to define Log() as "inline", which should get rid of the…

-OoREMOVEEMPTYPROCS

interesting!

why is it not available in
Lazarus through "all options" window (in project options / customizable options)?

(not sure about the names ... I have "opções personalizadas" and "todas as opções"!)

Philippe

Sven Barth wrote
Am 24.09.2014 10:15 schrieb "Tomas Hajny"

:

> However, the trunk compiler offers also another

option, although it may or

> may not be usable for you. In particular,

take the following:

Show quoted text 6 lines
> > --------- > var > S2: string; > >
procedure Log (S: string);
> begin > {$IFDEF TEST} > WriteLn
(S);
Show quoted text 6 lines
> {$ENDIF TEST} > end; > > begin > ReadLn (S2); > Log
('Input = ' + S2);
> end. > ========= > > If this is compiled

with trunk compiler using -OoREMOVEEMPTYPROCS (without

> -dTEST),

procedure Log is not called at all and the concatenation of

> strings

in its parameter is skipped as well.

Another possibility would be

to define Log() as "inline", which should get rid of the call and maybe the concatenation as well and already works in 2.6.x (though "array of const" would not be supported if needed)

Show quoted text 5 lines
Regards, Sven

Reply by email

Mattias Gaertner
to Philippe
Show quoted text 9 lines
-OoREMOVEEMPTYPROCS interesting! why is it not available in Lazarus through "all options" window (in project options / customizable options)?

It is available under Compiler Options / Other / All Options .... You need fpc 2.7.1 for this.

Mattias

Reply by email

Philippe
to Mattias Gaertner

and I am with 2.6.4 !!!!

thanks!

Mattias Gaertner wrote
On Wed, 24 Sep 2014 07:12:44 -0300 Philippe
> -OoREMOVEEMPTYPROCS interesting!

why is it not available in Lazarus through "all options" window (in project options / customizable options)?

It is available under

Compiler Options / Other / All Options ....

You need fpc 2.7.1 for

this.

Mattias _______________________________________________

fpc-pascal maillist -

http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal [1]

Links:
------
[1]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Florian Klämpfl
to Роман: As we all know, C preprocessor allows function-like macros, including ones with empty…
Роман wrote 28 lines
As we all know, C preprocessor allows function-like macros, including ones with empty expansion. They can be very convenient for things that you'll want to disable depending on conditional defines, such as logging or assertions. #ifdef DEBUG #define dprf(...) print_debug_message(__VA_ARGS__) #else #define dprf(...) #endif I have a temptation to use this in FPC too. Here's a trick: {$macro on} {$ifdef DEBUG} {$define Log := ActualLog} {$else} {$define Log := ;//} {$endif} if A then Log('will work until followed by ELSE at all or any statements on the same line (because of ; and //, respectively).'); if B then Log('And should not be carried over to the next line, of course!'); Because constant {$ifdef DEBUG} ActualLog(...); {$endif} are rather cumbersome. This is by design? Can I rely on this behavior in the future? ._.

As far as the example above is concerned, yes. Macros just do a textual replacement.

Reply by email