I've been gathering useful routines into a utilities unit which I then compile into a .DLL and a .DCU, so I can choose which method is convenient to access those routines.
For instance, I've written my own Lowcase which acts on [wide]chars or [wide]strings to implement the obvious function, bizarrely not implemented by Embarcadero.
Similarly, I've extended Max and Min to find Max/Min of an array of numerics.
In some cases, I've essentially simply provided an alias to an existing function, such as
function LowCase
(const st : ANSIstring
) : ANSIstring;
stdcall;
begin
result := ansilowercase(st);
end;
which would be exported to the DLL by
exports LowCase
(const st : ANSIstring
) name 'lowcaseansistr';
So far, so good.
I recently found that
var
v_uint64 : uint64;
v_uint64 := $FFFFFFFFFFFFFFFF;
writeln('v_uint64=',inttostr(v_uint64));
v_uint64 := $7FFFFFFFFFFFFFFF;
writeln('v_uint64=',inttostr(v_uint64));
produced an incorrect result in the first instance (-1) - in fact, wherever MSB is set, but is fine in the second case where MSB is clear.
So I found uinttostr
and substituting this standard function for inttostr
solved the issue.
ISTM it would be far more convenient if I could simply perform the alias trick again, so I tried (implementation)
function inttostr
(p_nb_int : uint64
) : string;
stdcall;
begin
result := uinttostr(p_nb_int);
end;
(interface)
function inttostr
(p_nb_int : uint64
) : string;
overload;
stdcall;
Which worked quite happily, but implementing
exports inttostr
(p_nb_int : uint64
) name 'uinttostr64';
in the project generated E2276 Identifier 'IntToStr' cannot be exported
. E2276 seems to be related to local directive
, apparently invoked by local;
in the declaration - but in the source provided by EMBT in System.Sysutils.pas, the declaration is
function IntToStr(Value: Integer): string; overload;
function IntToStr(Value: Int64): string; overload;
No local;
in sight!
So - I'm stumped. How do I get around this? (XE2)
Here's a test program:
program countparamsshort;
{$APPTYPE CONSOLE}
{$R *.res}
uses
dxutypes,
// dxumethods,
system.math,windows,vcl.Graphics,classes,System.SysUtils;
//{$I C:\delphi\dxu.inc}
var
v_int64 : int64 ; // -2^63..2^63-1
v_uint64 : uint64; // 0..2^64-1
procedure showv;
begin
writeln('v_int64= ',inttostr(v_int64));
writeln('v_uint64=',inttostr(v_uint64));
end;
begin
writeln('min values');
v_int64 := -214748364999;
v_uint64 := 0;
showv;
writeln('max values');
v_int64 := $FFFFFFFFFFFFFFFF;
v_uint64 := $FFFFFFFFFFFFFFFF;
showv;
writeln('max 63-bit values');
v_int64 := $7FFFFFFFFFFFFFFF;
v_uint64 := $7FFFFFFFFFFFFFFF;
showv;
// writeln(inttostr(max(10,3)),' & ',inttostr(max([1,12,7,9,11,4])));
writeln('procedure finished');
readln;
end.
Running as-is with the .dcu dxumethods and include file C:\delphi\dxu.inc commented-out invokes the system.math implementation of inttostr
with the resultant report
min values
v_int64= -214748364999
v_uint64=0
max values
v_int64= -1
v_uint64=-1
max 63-bit values
v_int64= 9223372036854775807
v_uint64=9223372036854775807
procedure finished
Which is NOT correct for v_uint64
. Invoking uinttostr
for a uint64
would cure the problem BUT that means remembering to do so.
Removing the comment from the dxumethods element means that my version of inttostr
is included - which actually executes uinttostr
. Results are:
min values
v_int64= -214748364999
v_uint64=0
max values
v_int64= -1
v_uint64=18446744073709551615
max 63-bit values
v_int64= 9223372036854775807
v_uint64=9223372036854775807
10 & 12
procedure finished
where the value of v_uint64
is now displayed correctly. This means that I can use inttostr
and can forget all about uinttostr
, so I don't have to sit here figuring out which I should use when. I've figured it out once, and now the compiler can do the work in future.
I've also un-commented-out the MAX
call which uses the same methodology to allow me to find the max
of an array - it means I can forget all about maxintvalue and maxvalue (it invokes those routines) but once again, I can simply use max
- whether the traditional version or the same concept with regard to arrays. Don't clutter up the mind with three routines (and another 3 for the MIN equivalents) when one will do.
Finally, re-commenting dxumethods and un-commenting the include file, which contains lines like
function inttostr
(p_nb_int : uint64
) : string;
overload;
stdcall;
external 'dxuproject.dll' name 'uinttostr64';
produced identical results, this time from the .DLL - the key being to qualify the function-name when constructing the .DLL else you trip over the E2276
error.
Now - WHY this occurs, when similar machinations around MAX/MIN
don't faze the compiler, I'll leave to the theoreticians - and what it has to do with 'local' declarations which seem to be a Kylix hangover - well, that's in the laps (or perhaps lapse) of the gods AFAICS.
Anyhow - good outcome; problem solved. Season's Greetings...