Recent

Author Topic: {$if SizeOf(byte) = 1} works but {$if SizeOf(TMyOrdinalType) = 1} doesn't  (Read 10716 times)

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
It really works
Example works, but redeclaring types is not possible so not applicable to my specific use case:

Code: Pascal  [Select][+][-]
  1. type TORDINALTYPE_ = type byte;
  2. {$define TORDINALTYPE:=Byte}
  3. {$i syshelpo.inc}
  4.  
  5. type TORDINALTYPE_ = type shortint;
  6. {$define TORDINALTYPE:=ShortInt}
  7. {$i syshelpo.inc}
  8.  

so for now I will be forced to do something like this:

Code: Pascal  [Select][+][-]
  1. {$define TORDINALTYPE:=Byte}
  2. {$define TORDINALBYTESIZE1}
  3. {$i syshelpo.inc}
  4. {$undef TORDINALBYTESIZE1}
  5.  
  6. {$define TORDINALTYPE:=word}
  7. {$define TORDINALBYTESIZE2}
  8. {$i syshelpo.inc}
  9. {$undef TORDINALBYTESIZE2}
  10.  
  11. ...
  12.  
  13. // content of syshelpo.inc:
  14.  
  15. function TORDINALHELPER.HighestBitPos: cardinal;
  16. begin
  17.   {$ifdef TORDINALBYTESIZE1}
  18.     Result := BsrByte(byte(Self));
  19.   {$endif}
  20.  
  21.   {$ifdef TORDINALBYTESIZE2}
  22.     Result := BsrWord(word(Self));
  23.   {$endif}
  24.  
  25.   {$ifdef TORDINALBYTESIZE3}
  26.     Result := BsrDWord(dword(Self));
  27.   {$endif}
  28.  
  29.   {$ifdef TORDINALBYTESIZE4}
  30.     Result := BsrQWord(qword(Self));
  31.   {$endif}                  
  32. end;

That does not have runtime performance penalty...
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
Macros can also be defined on the cmdline using the -dx:=y syntax.

And they are not just for types, classically macros in FPC were mostly used for calling conventions.

alpine

  • Hero Member
  • *****
  • Posts: 1032
What about:
Code: Pascal  [Select][+][-]
  1. function Bsr_(A: Byte): Cardinal; overload; inline; begin Result := BsrByte(A); end;
  2. function Bsr_(A: Word): Cardinal; overload; inline; begin Result := BsrWord(A); end;
  3. function Bsr_(A: DWord): Cardinal; overload; inline; begin Result := BsrDWord(A); end;
  4. function Bsr_(A: QWord): Cardinal; overload; inline; begin Result := BsrQWord(A); end;
  5. function Bsr_(A: ShortInt): Cardinal; overload; inline; begin Result := BsrByte(Byte(A)); end;
  6. function Bsr_(A: SmallInt): Cardinal; overload; inline; begin Result := BsrWord(Word(A)); end;
  7. function Bsr_(A: LongInt): Cardinal; overload; inline; begin Result := BsrWord(DWord(A)); end;
  8. function Bsr_(A: Int64): Cardinal; overload; inline; begin Result := BsrWord(DWord(A)); end;

and then:
Code: Pascal  [Select][+][-]
  1.   function TORDINALHELPER.HighestBitPos: cardinal;
  2.   begin
  3.     Result := Bsr_(Self);
  4.   end;

?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11351
  • FPC developer.
sizeof(atype) can also be queried in a $IF, so has no runtime penalty.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
It really works, so I guess I should probably file a feature bug report. Thanks a lot!  :D :) :D
I'm not sure it is a bug. IMHO I'd prefer not to have a macro expansion within a conditional directive. I even wonder why {$DEFINE :=} was introduced at first place, we have const, type  ... In C that was the only way to define (literal) constants.

Because the people who designed C were humble enough to realise that they couldn't cover all cases?

I found myself writing this the other day:

Code: Pascal  [Select][+][-]
  1. {$MACRO ON}
  2. {$DEFINE MANDATORY_BREAK:=try Assert(false, 'Terra Incognita (here be dragons!)') except end }
  3.  
Code: Pascal  [Select][+][-]
  1.   if IsDebuggerPresent() then
  2.     MANDATORY_BREAK;
  3.  

...and it would be even more useful if parameters were supported so that the message didn't have to be fixed.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 3921
...and it would be even more useful if parameters were supported so that the message didn't have to be fixed.
A small inline function could take a parameter and, being inline, its overhead would be very similar to that of a macro.  Would that be helpful ?
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
...and it would be even more useful if parameters were supported so that the message didn't have to be fixed.
A small inline function could take a parameter and, being inline, its overhead would be very similar to that of a macro.  Would that be helpful ?

I don't think so in that specific case, since the error message (assertion) would still indicate the point of definition rather than the point of invocation.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1311
    • Lebeau Software
As said, I am trying to avoid runtime SizeOf() and case block check.

SizeOf() is never evaluated at runtime, it is a compile-time constant.  Thus, in code like this:

Code: Pascal  [Select][+][-]
  1. function TORDINALHELPER.HighestBitPos: Cardinal;
  2. begin
  3.   case SizeOf(TORDINALTYPE) of
  4.     1: Result := BsrByte(Byte(Self));
  5.     2: Result := BsrWord(Word(Self));
  6.     4: Result := BsrDWord(DWord(Self));
  7.     8: Result := BsrQWord(QWord(Self));
  8.   else
  9.     Result := 0;
  10.   end;
  11. end;

The case statement is being passed a constant, so the compiler knows exactly what the value is and can optimize away all of the unused cases at compile-time, thus leaving only the 1 usable case to be executable at runtime.
« Last Edit: July 16, 2021, 07:45:35 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

440bx

  • Hero Member
  • *****
  • Posts: 3921
I don't think so in that specific case, since the error message (assertion) would still indicate the point of definition rather than the point of invocation.
True but, you could pass the line number as a parameter to the inline function.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
The case statement is being passed a constant, so the compiler knows exactly what the value is and can optimize away all of the unused cases at compile-time, thus leaving only the 1 usable case to be executable at runtime.
If that is so then it is tempting to let compiler handle it, however for this specific case I will choose more control over less control.

Thanks everyone. It's been fun and educational!  8)
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

MarkMLl

  • Hero Member
  • *****
  • Posts: 6646
I don't think so in that specific case, since the error message (assertion) would still indicate the point of definition rather than the point of invocation.
True but, you could pass the line number as a parameter to the inline function.

Yes, obviously. But at that point you'd get TWO line numbers in the error message.

Later: https://wiki.ztex.de/doku.php?id=en:software:compilation:bmp looks interesting: a preprocessor written in FPC by a company selling FPGA development stuff.

Irrespective of the merits or hazards of any particular preprocessor, what I'd like to see is an FPC option so that if the developer had a good reason for wanting to use one he could tell the compiler to do so. However there's the obvious limitation that any substitution would have to be single-line, since FPC doesn't have an equivalent of C's #line directive.

MarkMLl
« Last Edit: July 16, 2021, 10:53:17 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Seenkao

  • Hero Member
  • *****
  • Posts: 545
    • New ZenGL.
Code: Pascal  [Select][+][-]
  1.   {$MACRO ON}
  2.   {$if SizeOf(byte) = 1}
  3.     WriteLn('SizeOf(byte) = ', SizeOf(byte));
  4.   {$endif}
  5.  
Возник ещё один вопрос: а для чего это вообще можно использовать? Мы заранее знаем, что размерность байта равна единице, и так же знаем размерности других данных.

Google translate:
Another question arose: why can it be used at all? We know in advance that the dimension of a byte is equal to one, and we also know the dimensions of other data.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
why can it be used at all? We know in advance that the dimension of a byte is equal to one, and we also know the dimensions of other data.
Original idea was to use {$if SizeOf(TMyOrdinalType) = 1} but since that didn't compile I quickly put several $if SizeOf tests to see what can actually pass. So {$if SizeOf(byte) = 1} and similar nonsenses are left overs after simple validation and confirmation tests. They do not have real use outside of testing.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
The case statement is being passed a constant, so the compiler knows exactly what the value is and can optimize away all of the unused cases at compile-time, thus leaving only the 1 usable case to be executable at runtime.
If that is so then it is tempting to let compiler handle it, however for this specific case I will choose more control over less control.

The use of a case-statement with either SizeOf(TORDINALTYPE) or SizeOf(Self) is in my opinion the most favored one as it doesn't rely on the preprocessor and thus looks nicer in code (and FPC can do constant folding for ordinal case-statements since 3.2.0 or even 3.0.0). Also it does not need "unifying overloads" as you suggested in your other post.

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
The use of a case-statement with either SizeOf(TORDINALTYPE) or SizeOf(Self) is in my opinion the most favored one as it doesn't rely on the preprocessor and thus looks nicer in code
If affected code is longer then what can fit in a single view of the editor, then I completely agree. Otherwise I do not mind that much for simple and short code parts that do not tend to change much in the future.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

 

TinyPortal © 2005-2018