Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Convert C-Builder program to Delphi?

0 views
Skip to first unread message

W. D.

unread,
Dec 28, 2004, 2:39:32 AM12/28/04
to
Hi Folks,

My Delphi is rusty, and my C is corroded. Am I
understanding this properly?

CPP Code:

TMainForm *MainForm

Is this a declaration for a form named 'MainForm'
that is of type 'TMainForm'? Does the asterisk
indicate that it is a pointer, and hence not
stored in the 64K heap?

Would the Delphi equivalent be:

type
MainForm: class(TMainForm);

If so, where does the pointer go?


In the following code, what is the Delphi equivalent
of 'void __fastcall'?

void __fastcall TMainForm::Button1Click(TObject *Sender)
{
// Do some stuff
}

Why isn't 'MainForm' used instead of 'TMainForm'? I
thought 'TMainForm' was a type!

Also, why the double colons '::' ?

And, why the '*' preceding 'Sender'?

What would be the Delphi equivalent of the above
function?

I do sincerely apologize for these basic questions,
but I've been Googling like crazy and can't find
much on translating from Borland C Builder to
Delphi.

Many, many thanks for any help you can provide!!!

Maarten Wiltink

unread,
Dec 28, 2004, 3:57:01 AM12/28/04
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41D10D...@US-Webmasters.com...

> My Delphi is rusty, and my C is corroded.

Er... obviously. No offense.


> Am I understanding this properly?
>
> CPP Code:
>
> TMainForm *MainForm
>
> Is this a declaration for a form named 'MainForm'
> that is of type 'TMainForm'? Does the asterisk
> indicate that it is a pointer, and hence not
> stored in the 64K heap?

Put a semicolon at the end, and it's a definition (allocates space,
as opposed to a declaration which only tells you the type so you can
use it) for the variable MainForm, of type pointer to TMainForm.

This is likely to be a global (source file scope) variable, putting
the pointer in the data segment. The dynamically allocated form, if
any, will be allocated in the heap. The heap is no longer limited
to 64KB.


> Would the Delphi equivalent be:
>
> type
> MainForm: class(TMainForm);

type
TMainForm = class(TForm)
...
end;

var
MainForm: TMainForm;


> If so, where does the pointer go?

Class types (objects) are pointers implicitly.


> In the following code, what is the Delphi equivalent
> of 'void __fastcall'?
>
> void __fastcall TMainForm::Button1Click(TObject *Sender)
> {
> // Do some stuff
> }

procedure TMailForm.Button1Click(Sender: TObject); register;
begin
{ Do some stuff }
end;

C doesn't distinguish between procedures (no return value) and
functions. Instead, it defines a function which returns the
pseudotype "void". Void is "no type" or "no value".

The __fastcall is a calling convention and the Delphi equivalent is
"register"... I think. This is the default calling convention in Delphi,
so it is not usually used explicitly. The Delphi IDE will generate the
above event handler without it.


> Why isn't 'MainForm' used instead of 'TMainForm'? I
> thought 'TMainForm' was a type!

It is. The type determines what methods are in it, not every instance
for itself. That would defeat the idea of types.


> Also, why the double colons '::' ?

They're C++ syntax for object type namespaces.


> And, why the '*' preceding 'Sender'?

Because in C++, object variables are explicitly pointers. In Delphi,
they're implicit pointers. They _are_ pointers, but the "^" is left
out of the syntax because it doesn't add anything we don't already
know. This is a difference in philosophy between C and Pascal: to C,
it's important to mirror as accurately as possible what happens at
the bare metal, while Pascal shields programmers from more things,
and bases itself more on high-level language constructs instead of
the underlying machine language.

Groetjes,
Maarten Wiltink


Rudy Velthuis

unread,
Dec 28, 2004, 7:26:54 AM12/28/04
to
W. D. wrote:

> Hi Folks,
>
> My Delphi is rusty, and my C is corroded. Am I
> understanding this properly?
>
> CPP Code:
>
> TMainForm *MainForm
>
> Is this a declaration for a form named 'MainForm'
> that is of type 'TMainForm'? Does the asterisk
> indicate that it is a pointer, and hence not
> stored in the 64K heap?

Yes, but the heap is much larger than that, nowadays.

> Would the Delphi equivalent be:
>
> type
> MainForm: class(TMainForm);

No, it is the same as:

var
MainForm: TMainForm;

In Delphi, objects are always pointers, but the ^ is not specified.
This is not so in C++, so you must specify the asterisk.



> In the following code, what is the Delphi equivalent
> of 'void __fastcall'?

Use the "register" directive, but since this is the default calling
convention in Delphi, there is no need to specify it.

> void __fastcall TMainForm::Button1Click(TObject *Sender)
> {
> // Do some stuff
> }

procedure TMainForm.Button1Click(Sender: TObject);
begin
// Do some stuff
end;


> Why isn't 'MainForm' used instead of 'TMainForm'? I
> thought 'TMainForm' was a type!

No, it isn't. You thought wrong. <g>



> Also, why the double colons '::' ?

Used in C++ to specify members of a class.



>
> And, why the '*' preceding 'Sender'?

See above.

--
Rudy Velthuis http://rvelthuis.bei.t-online.de

"I never miss a chance to have sex or appear on television."
- Gore Vidal

Maarten Wiltink

unread,
Dec 28, 2004, 9:37:59 AM12/28/04
to
"Rudy Velthuis" <rvel...@gmx.de> wrote in message
news:xn0drjtjudz2yhx...@www.teamb.com...
> W. D. wrote:
[...]

>> void __fastcall TMainForm::Button1Click(TObject *Sender)
>> {
>> // Do some stuff
>> }
[...]

>> Why isn't 'MainForm' used instead of 'TMainForm'? I
>> thought 'TMainForm' was a type!
>
> No, it isn't. You thought wrong. <g>

Er... come again?

Groetjes,
Maarten Wiltink


Rudy Velthuis

unread,
Dec 28, 2004, 11:48:22 AM12/28/04
to
Maarten Wiltink wrote:

> >> Why isn't 'MainForm' used instead of 'TMainForm'? I
> >> thought 'TMainForm' was a type!
> >
> > No, it isn't. You thought wrong. <g>
>
> Er... come again?

Oops, I meant MainForm isn't a type.

"I'm Jewish. I don't work out. If God had wanted us to bend over, He
would have put diamonds on the floor." -- Joan Rivers.

VBDis

unread,
Dec 29, 2004, 5:06:58 AM12/29/04
to
Im Artikel <41d11fe0$0$6211$e4fe...@news.xs4all.nl>, "Maarten Wiltink"
<maa...@kittensandcats.net> schreibt:

>> And, why the '*' preceding 'Sender'?
>
>Because in C++, object variables are explicitly pointers. In Delphi,
>they're implicit pointers. They _are_ pointers, but the "^" is left
>out of the syntax because it doesn't add anything we don't already
>know.

I also (often) don't understand why "*" is used instead of "&". The C "*"
corresponds to Delphi pointers, whereas the C++ "&" corresponds to Delphi
references (i.e. class instances, var parameters...), with the same pointerless
notation in C++ code.

There exists only one difference, in so far as C++ "&" reference arguments
never can be NULL/nil. This is also true for Delphi "var" parameters, but not
for "Self" in class methods.


BTW, thanks for your very good contribution :-)

DoDi

W. D.

unread,
Jan 3, 2005, 3:51:07 AM1/3/05
to
Thanks everyone for your help on this problem! I really do
appreciate the thought and time you put into your answers to
my questions.

After quite a few attempts at adding the forms, I found
that the easiest way to do it is to open up both C-Builder
and Delphi to the "Project Manager". This is done by
mousing to: View -> Project Manager (Shortcut: Ctrl-Alt-F11).
Once this window is open in both environments, try to make
the Delphi project structure look exactly like the C-Builder
structure.

For each .pas file, just put together a very short, syntactically
correct file like Walter suggested:

=================================================================
unit Unit1;

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls;

interface

type
TForm1 = class(TForm)
end;

implementation
{$R *.dfm}

end.
=================================================================

Highlight the proper place in the Project Manager, then mouse to:
Project -> Add to Project (Shortcut: Shift-F11). This will
add the .pas file in the proper place relative to all the other
elements. Once the .pas file is added, add the form (.dfm) right
next to it. When these forms are added, the event handlers
are forced to be discarded.

After having done this, I now have a structure that looks
very much like the C-Builder program, and the forms in
the Delphi project are exactly the same.

However, I am running into rough territory translating the
code. (As I mentioned before, both my Delphi and C coding
skills are quite rusty--although it is coming back to me
fairly quickly.)

I've been trying to incorporate the .h files into the
Interface section of one unit. Ralph's suggestion
of putting the C++ code into a comment just before
the Delphi translation helps to understand things more
clearly. This is a medium sized program, so I've
resorted to writing some regular expressions in order
to convert much of the simpler code.

However, I can't seem to find the proper way to
translate some entries in the .h file. Does anyone
have some idea what might be appropriate?

#1:
--------------------------------------------------------
extern TMainForm *MainForm;
--------------------------------------------------------

#2:
--------------------------------------------------------
typedef struct
{
BYTE header[8];
BYTE *data;
DWORD size;
}
DATA_STORE;
--------------------------------------------------------

#3:
--------------------------------------------------------
extern int MAX_STORED_UNITS;
--------------------------------------------------------

#4:
--------------------------------------------------------
extern THE_BUFFER *buffer;
--------------------------------------------------------

#5:
--------------------------------------------------------
extern DWORD req_data;
--------------------------------------------------------

Again, I really appreciate any shoves in the proper
direction on all this. I've been digging through Google
and GoogleGroups for much of this, but there's not a lot
out there.

Maarten Wiltink

unread,
Jan 3, 2005, 4:27:32 AM1/3/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41D907...@US-Webmasters.com...
[...]

> However, I can't seem to find the proper way to
> translate some entries in the .h file. Does anyone
> have some idea what might be appropriate?

> #1, 3..5:
> --------------------------------------------------------
> extern TMainForm *MainForm;
> extern int MAX_STORED_UNITS;
> extern THE_BUFFER *buffer;
> extern DWORD req_data;
> --------------------------------------------------------

These are all variable declarations. In C, an explicit separation is
made between declarations and definitions. Declarations tell the compiler
that a variable (or function!) may be expected to exist and has some type.
A definition _makes_ it exist, by allocating space in the data segment or
the stack, and of course also gives it a type.

Declarations go into header files, so that everybody may include them.
Definitions go into source files and occur only once.

It's possible to declare a variable (a hundred times over) but forget to
define it. I don't know if that's a linker error or if it's then defined
implicitly.


> #2:
> --------------------------------------------------------
> typedef struct
> {
> BYTE header[8];
> BYTE *data;
> DWORD size;
> }
> DATA_STORE;
> --------------------------------------------------------

A simple type declaration.

type DATA_STORE = record
header: array [1..8] of Byte;
data: PByte;
Size: Cardinal;
end;

Groetjes,
Maarten Wiltink


Maarten Wiltink

unread,
Jan 3, 2005, 5:33:05 AM1/3/05
to
"Maarten Wiltink" <maa...@kittensandcats.net> wrote in message
news:41d91044$0$6205$e4fe...@news.xs4all.nl...

> "W. D." <NewsG...@US-Webmasters.com> wrote in message
> news:41D907...@US-Webmasters.com...
> [...]
>> However, I can't seem to find the proper way to
>> translate some entries in the .h file. Does anyone
>> have some idea what might be appropriate?
>
>> #1, 3..5:
>> --------------------------------------------------------
>> extern TMainForm *MainForm;
>> extern int MAX_STORED_UNITS;
>> extern THE_BUFFER *buffer;
>> extern DWORD req_data;
>> --------------------------------------------------------

<declarations vs. definitions>

What I forgot to say here is that the appropriate way to translate
external declarations to Delphi is "uses <unit>;". That's really
the translation of "#include <header>", an intermediate step to
the actual declarations that is widespread in C as well.

But in C, you can actually interject an "int printf();" in your
code to get the compiler to allow calling an as yet unimplemented
function printf in the expectation that someone, somewhere, will
make it accessible. There is no substitute for that in Pascal;
you have to point the compiler at a source file from which it will
extract a list of public identifiers.

Groetjes,
Maarten Wiltink


W. D.

unread,
Jan 14, 2005, 4:46:48 AM1/14/05
to
Thanks, guys, for your answers to my previous questions!
I am slowy but surely(?) getting this C++ code
converted to Delphi.

In the process of translating, I need to combine
the .h (header) files, and the .CPP (implementation)
into a single Delphi unit.

In one unit, I've translated a fairly complicated
class, but the CPP file contains some lines
(put in the Implementation block) that I don't know
how to translate. These variables have
all been previously declared in the class. They
all seem to be 'static' variables.

=======================================================
// Static Class Members:
uint16 TheMainClass::Some_Table[256];
uint8 TheMainClass::Some_Table_Exists = false;

char TheMainClass::VersionFlag = 'A';
int TheMainClass::MajorVersion = '7';
int TheMainClass::MinorVersion = 00;
char TheMainClass::VersionStr[40];
=======================================================

This block of code comes just before the
Constructor definition. It comes just after all of
the '#include' lines.

Before this implementation block, I have the
Interface section that has been translated from
the .h (header) file.

Does anyone have any idea on how to translate this
block of code? I've tried all sorts of variations,
but the compiler just chokes on them all.

Maarten Wiltink

unread,
Jan 14, 2005, 9:09:13 AM1/14/05
to
"W. D." <Google...@US-Webmasters.com> wrote in message
news:1105696007.9...@z14g2000cwz.googlegroups.com...
[...]
> // Static Class Members:

Static class members are associated with the class, not repeated
in every instance. Older versions of Delphi for win32 do not have
any support for this at all, I think it was introduced with D2005
because it needed to support it on .Net anyway.

Use global (unit-scope) variables instead. Normally you put them in
the implementation section, making them invisible outside the unit.
They are not in the class but code that _is_ in the class can
access them because they're in the same unit.

Groetjes,
Maarten Wiltink


Martin Harvey (Demon account)

unread,
Jan 15, 2005, 7:19:39 PM1/15/05
to
On Fri, 14 Jan 2005 15:09:13 +0100, "Maarten Wiltink"
<maa...@kittensandcats.net> wrote:

>Use global (unit-scope) variables instead. Normally you put them in
>the implementation section, making them invisible outside the unit.
>They are not in the class but code that _is_ in the class can
>access them because they're in the same unit.

I might add that by the looks of some of those variables, a const
would be more appropriate.

MH.

VBDis

unread,
Jan 16, 2005, 4:23:44 AM1/16/05
to
Im Artikel <1105696007.9...@z14g2000cwz.googlegroups.com>, "W. D."
<Google...@US-Webmasters.com> schreibt:

>// Static Class Members:
>uint16 TheMainClass::Some_Table[256];
>uint8 TheMainClass::Some_Table_Exists = false;

These all are (initialized) variables. Since Delphi has no static fields,
you'll have to implement "class" properties instead, e.g.:

Add the methods to the class:

class function GetSomeTableExists: boolean;
class procedure SetSomeTableExists(newval: boolean);
property Some_Table_Exists: boolean read GetSomeTableExists write
SetSomeTableExists;
//property not tested, hope it compiles...

Then, in the implementation section, add the variable and the implementation of
the methods:

var TheMainClass_Some_Table_Exists: boolean = false;

class function TheMainClass.GetSomeTableExists: boolean;
begin
Result := TheMainClass_Some_Table_Exists;
end;

class procedure TheMainClass.SetSomeTableExists(newval: boolean);
begin
TheMainClass_Some_Table_Exists := newval;
end;

It's like implementing "normal" properties, with the difference of the "class"
methods and the variable residing outside the class declaration.

DoDi

W. D.

unread,
Jan 17, 2005, 5:40:05 PM1/17/05
to
Many, many thanks for all your help!!!! You have helped me trudge
along in this project.

Right now I am stumped on some fairly simple C code that
initializes a packed struct/record:

memset(&PackedStruct, 0, sizeof(PackedStruct));

Does anyone have some idea how to do this in Delphi?

W. D.

unread,
Jan 18, 2005, 1:21:59 AM1/18/05
to NewsG...@us-webmasters.com

Many thanks to Stephen Posey!...who suggested:

FillChar(PackedStruct, SizeOf(TPackedStruct), 0);

Now I am stumped again with a 'new' dynamic allocation
line:

PackedStruct.maindata = new uint8[MAX_DATA_LEN];

I looked around: in the Help file, here:
http://www.delphibasics.co.uk/RTL.asp?Name=New
and other places on the 'Net, but not sure
what to do. Can this statement be done on
one line in Delphi?

FYI, the RECORD type looks similar to this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;
CRC: UINT16;

// In the C++ code there is something like:
// Packed_Struct()
// ~Packed_Struct()

// Are these by chance constructor and destructor?
// If so, would this code make sense:

// Constructor Create;
// Destructor Destroy; Override;

end; // Packed_Struct


Again, thanks a bunch for any help you can provide!

(I apologize for emailing you directly. :-(
I'll just post to the various forums from now on)

Maarten Wiltink

unread,
Jan 18, 2005, 5:31:46 AM1/18/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41ECAB...@US-Webmasters.com...
[...]

> Now I am stumped again with a 'new' dynamic allocation line:
>
> PackedStruct.maindata = new uint8[MAX_DATA_LEN];

It's a simple memory allocation for an array of uint8s (bytes),
MAX_DATA_LEN of them. The simplistic Delphi equivalent is GetMem,
the idiomatic Delphi equivalent would be SetLength'ing a dynamic
array.


[...]


> FYI, the RECORD type looks similar to this:
>
> type
> Packed_Struct = PACKED record
> soh: UINT8;
> Data_Type: UINT8;
> Data_Size: UINT16;
> maindata: UINT8;

...But maindata would need to be a pointer to uint8 for the
above to be valid. While UINT8 is not equal to uint8 in C++, I
doubt that it means anything different. It seems unlikely that
an indirection (pointer) would be introduced without so much as
a hint.

But then, you say "similar". It doesn't look like C++, either.
Please copy and paste actual compiling code next time, so we
don't have to guess what mistakes were introduced in retyping.


> CRC: UINT16;
>
> // In the C++ code there is something like:
> // Packed_Struct()
> // ~Packed_Struct()
>
> // Are these by chance constructor and destructor?
> // If so, would this code make sense:
>
> // Constructor Create;
> // Destructor Destroy; Override;

Yes. It would make sense, but there are subtleties. The C++ type
is a record that could be "instantiated" on the stack, by declaring
a variable that holds the record. Delphi class types are always on
the heap, and are always a pointer away.

Constructors and destructors have slightly different semantics in
C++ and Delphi. That's minor, though, compared to the differences in
memory allocation.


> end; // Packed_Struct
[...]


> (I apologize for emailing you directly. :-(
> I'll just post to the various forums from now on)

That's the idea.

Groetjes,
Maarten Wiltink


Message has been deleted
Message has been deleted

W. D.

unread,
Jan 18, 2005, 5:11:31 PM1/18/05
to
At 00:49 1/18/2005, Stephen Posey wrote:
>Yep, looks like a static class (basically a record with methods), which
>Delphi doesn't support (not 100% strictly true, but the way to do it is
>deprecated and you probably would be better served by going about it a
>dfferent way).
>
>The way this is being used, it looks like "maindata" is being treated as
>a pointer rather than a strict UINT8 field, are you sure there's not a
>"*" in the original C++ declaration somewheres?

Right you are: UINT8 *maindata; // Pointer to maindata


>Anyway, assuming that's the case, the statement appears to be allocating
>memory for the data, so something like this should suffice:
>
> GetMem(PackedStruct.maindata, MAX_DATA_LEN);


Are these constructors and destructors?

Packed_Struct()
~Packed_Struct()

If so, would this be the proper translation?

Constructor Create;
Destructor Destroy; Override;

>If you can't figure out how maindata is being used as a pointer, please
>post some more context code so I can see more exactly what's going on
>with it.
>
>My guess is that there's a more Delphi-like way of going about this
>involving pointers to array types, or perhaps using a dynamic array,
>depending on how it's actually being used in the code.

Hmmm. Would that mean declaring the packed record type then
declaring a pointer to that record, like this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;
CRC: UINT16;

Constructor Create;
Destructor Destroy; Override;

end; // Packed_Struct

Var
PkdStrPtr: ^Packed_Struct;

????

Thanks!!!!!!!!!

Bjørge Sæther

unread,
Jan 19, 2005, 8:57:11 AM1/19/05
to
W. D. wrote:

FillChar(TheRecord, SizeOf(TheRecord), 0);

W. D.

unread,
Jan 19, 2005, 6:20:08 PM1/19/05
to

Thanks, Bjørge! (and Maarten!)


Is anyone familiar with 'strtol'? What the heck is a radix?

m_TheType = strtol(&SomeVar[5], NULL, 16);

I tried a 'StrToInt' but the format is different.

red floyd

unread,
Jan 19, 2005, 7:21:35 PM1/19/05
to
W. D. wrote:

>
> Is anyone familiar with 'strtol'? What the heck is a radix?

A base. (base 2, base 10, base 16...)

W. D.

unread,
Jan 20, 2005, 2:10:19 AM1/20/05
to

OK, Thanks Red Floyd!

I just used:
m_TheType := StrToInt(SomeVar[5]);

It compiled OK. We'll see if it runs--I'll be amazed if
this thing doesn't crash right out of the gate. ;^)

This program is throwing another monkey wrench at me:

===================================
#if defined (PROC_PAUSE)

volatile bool bPauseProc;

#endif
===================================

Although I found a very nice description of 'volatile':
http://www.programmersheaven.com/articles/pathak/article1.htm ,

I couldn't find any equivalent keyword that will disallow
compiler optimizations in Delphi. Any hints?

Marco van de Voort

unread,
Jan 20, 2005, 9:11:21 AM1/20/05
to
On 2005-01-20, W. D. <NewsG...@US-Webmasters.com> wrote:
> this thing doesn't crash right out of the gate. ;^)
>
> This program is throwing another monkey wrench at me:
>
>===================================
> #if defined (PROC_PAUSE)
>
> volatile bool bPauseProc;
>
> #endif
>===================================
>
> Although I found a very nice description of 'volatile':
> http://www.programmersheaven.com/articles/pathak/article1.htm ,
>
> I couldn't find any equivalent keyword that will disallow
> compiler optimizations in Delphi. Any hints?

There isn't. Protect the var with a mutex.

W. D.

unread,
Jan 21, 2005, 6:13:37 PM1/21/05
to

Thanks, Marco!

I've just commented out the code for now. We'll see if it
explodes when I get the whole program to compile.

Just now I've been thrown a 'pointer' curve ball:

Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);


I realize that this is casting the PackedStruct as
an array of bytes, and we are trying to collect 7
bytes to put into Temp32 starting at the first
byte. (Temp32 is a uint32).

Does anyone have an idea why I would get errors
using this?
Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

Is there some better way to do this?

Maarten Wiltink

unread,
Jan 22, 2005, 4:13:00 PM1/22/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41F18C...@US-Webmasters.com...
[...]

> Just now I've been thrown a 'pointer' curve ball:
>
> Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);
>
>
> I realize that this is casting the PackedStruct as
> an array of bytes, and we are trying to collect 7
> bytes to put into Temp32 starting at the first
> byte. (Temp32 is a uint32).

Second byte, actually.


> Does anyone have an idea why I would get errors
> using this?
> Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));
>
> Is there some better way to do this?

Same mistake as last time. (uint8 *) is a PByte, not a byte.

It looks like odd C code anyway. &x[1] should be written as x+1,
and apparently indexing has higher priority than taking the
address, but I'd be using more parentheses _and_ more temporary
variables.

Groetjes,
Maarten Wiltink


W. D.

unread,
Jan 23, 2005, 2:06:39 AM1/23/05
to Maarten Wiltink
Thanks again, Maarten! I do appreciate you pointing
me in the proper direction.

I'm still having problems with this, though. Below is
what I've come up with so far:

// Declared this temporary variable:
Var
BytePointer: ^Byte;

BytePointer := Addr(packet); // This compiles.

Temp32 := GetChunk(7, BytePointer^); // This also compiles.

However, this code presumable references the FIRST byte of
data. As you correctly pointed out, we are trying to
suck in 7 bytes starting at the SECOND byte.

Any time I tried to do something like:

BytePointer := Addr(packet) +1; // or,
Temp32 := GetChunk(7, (BytePointer +1)^ );

the compiler can't figure out that I want to start at the
next byte. Any ideas on how to "phrase" this properly?

Also, should I dipose of these temporary pointer variables
at the end of the function or procedure?

Thanks in advance for helping me stop stumbling around in
the dark!

Maarten Wiltink

unread,
Jan 23, 2005, 7:23:06 AM1/23/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41F34C...@US-Webmasters.com...

> Maarten Wiltink wrote:
>> "W. D." <NewsG...@US-Webmasters.com> wrote in message
>> news:41F18C...@US-Webmasters.com...

>>> Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);
[...]


>>> Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

[...]


>> Same mistake as last time. (uint8 *) is a PByte, not a byte.

[...]


> // Declared this temporary variable:
> Var
> BytePointer: ^Byte;
>
> BytePointer := Addr(packet); // This compiles.
>
> Temp32 := GetChunk(7, BytePointer^); // This also compiles.
>
> However, this code presumable references the FIRST byte of
> data. As you correctly pointed out, we are trying to
> suck in 7 bytes starting at the SECOND byte.
>
> Any time I tried to do something like:
>
> BytePointer := Addr(packet) +1; // or,
> Temp32 := GetChunk(7, (BytePointer +1)^ );
>
> the compiler can't figure out that I want to start at the
> next byte. Any ideas on how to "phrase" this properly?

The compiler knows that BytePointer is a pointer to byte, but
Addr() returns a Pointer, an untyped pointer. That can be assigned
to any typed pointer but it does not have an "element size" of
itself. You can either cast the Addr() to a pointer to byte and
add, or add to BytePointer (in a new statement).

Adding one to a Pointer isn't, or shouldn't be, allowed. This
may vary between versions. Adding one to a pointer to byte
should be allowed and dereferencing that pointer also. Please
post actual compiled code and exact error messages and cursor
locations.

(BytePointer+1)^ can be written as BytePointer[1].


> Also, should I dipose of these temporary pointer variables
> at the end of the function or procedure?

Did you allocate the memory they point to? That should normally
tell you if you need to free it.

In this case, it points halfway into Packet. You could try to
dispose its second half just once if you want to see the fireworks.
But that's not how memory allocation works.

Groetjes,
Maarten Wiltink


VBDis

unread,
Jan 23, 2005, 7:36:30 PM1/23/05
to
Im Artikel <41F18C...@US-Webmasters.com>, "W. D."
<NewsG...@US-Webmasters.com> schreibt:

> Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);

>I realize that this is casting the PackedStruct as
>an array of bytes, and we are trying to collect 7
>bytes to put into Temp32 starting at the first
>byte. (Temp32 is a uint32).

IMO it's starting at the second byte, since C arrays are always zero-based.

>Does anyone have an idea why I would get errors
>using this?
> Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

There's one Addr too much :-(
Try:

type Tuint8Array = array[0..7] of uint8;
Temp32 := GetChunk(7, Addr(Tuint8array(PackedStruct)[1]));

DoDi

W. D.

unread,
Jan 27, 2005, 1:20:58 AM1/27/05
to


Thanks DoDi! I'll try that when I get back to it. Right now
this C++ code that I am working on is getting bizzare. As far
as I can tell, the following code is for compatibilty with DLLs.

I Googled just about everyplace I can think of and still
haven't come up with the proper way to translate these
to Delphi:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if !defined (DLLFUNC)
#define DLLFUNC(ret) extern __declspec(dllexport) ret __stdcall
#endif


DLLFUNC(int) SomeDLL_Open();

DLLFUNC(void) SomeDLL_Close();

DLLFUNC(int) SomeDLL_GetData(BYTE* pDataType, const PBYTE* pTheData,
DWORD* pDataSize);

DLLFUNC(int) SomeDLL_Request(BYTE byRequestType, DWORD dwRequestData);

// The result returned is based upon the last function attempted within
this DLL
DLLFUNC(int) SomeDLL_GetErrorCondition();

typedef int (__stdcall *FUNC_OPEN)();
typedef void (__stdcall *FUNC_CLOSE)();
typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);
typedef void (__stdcall *FUNC_SHOWICON)(BOOL);


#endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Can anybody spare a hint?

Mucho gracias if you can help!

Maarten Wiltink

unread,
Jan 27, 2005, 8:56:02 AM1/27/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41F888...@US-Webmasters.com...

> [...] Right now this C++ code that I am working on is getting


> bizzare. As far as I can tell, the following code is for
> compatibilty with DLLs.
>
> I Googled just about everyplace I can think of and still
> haven't come up with the proper way to translate these
> to Delphi:
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> #if !defined (DLLFUNC)
> #define DLLFUNC(ret) extern __declspec(dllexport) ret __stdcall
> #endif
>
> DLLFUNC(int) SomeDLL_Open();

DLLFUNC(T) more or less wraps type T so that declaring a function
to return it is also usefully exported from a DLL this source is
linked into.

It is a macro and depends on C preprocessor macros being textual;
also on the syntactical closeness of the relevant C keywords.
Delphi does not have them all next to each other and doesn't have
macros anyway.

Marking functions as exported is done in the project file in Delphi,
quite separate from the function declaration itself. The calling
convention is given by a directive added after the declaration but
it marks up the declaration as a whole, not just the type. (That's
true also for C, but macros don't care.)

Look for "exports" and "stdcall" in the help.

Groetjes,
Maarten Wiltink


W. D.

unread,
Jan 28, 2005, 1:42:01 AM1/28/05
to
At 11:53 1/27/2005, Stephen Posey wrote:
>> Oh boy. This C++ code that I am working on is getting
>> bizzare. As far as I can tell, this code is for compatibilty with DLLs.
>>
>> I Googled just about everyplace I can think of and still haven't come up
>with
>> the proper way to translate these to Delphi:
>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> #if !defined (DLLFUNC)
>> #define DLLFUNC(ret) extern __declspec(dllexport) ret __stdcall #endif
>>
>>
>> DLLFUNC(int) SomeDLL_Open();
>>
>> DLLFUNC(void) SomeDLL_Close();
>>
>> DLLFUNC(int) SomeDLL_GetData(BYTE* pDataType, const PBYTE* pTheData,
>DWORD* pDataSize);
>>
>> DLLFUNC(int) SomeDLL_Request(BYTE byRequestType, DWORD dwRequestData);
>>
>> // The result returned is based upon the last function attempted within
>this DLL
>> DLLFUNC(int) SomeDLL_GetErrorCondition();
>>
>> typedef int (__stdcall *FUNC_OPEN)();
>> typedef void (__stdcall *FUNC_CLOSE)();
>> typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);
>> typedef void (__stdcall *FUNC_SHOWICON)(BOOL);
>>
>>
>> #endif
>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Can anybody spare a hint?
>
>This appears to me to be an overly cute approach of defining a
>consistent interface onto some exported DLL functions. I guess it might
>have some benefit if the calling signature is expected to change, this
>way the only place anything needs to be changed is in the #define macro.
>
>The thing to remember about C/C++ preprocessor #defines is that it's
>really just a TEXT substitution mechanism. Since Delphi doesn't have
>anything quite like this, the usual approach is to expand the #define
>into actual Delphi code; sometimes this comes out as a CONST
>declaration, sometimes it converts to a function, in this case it
>decorates some function declarations elsewhere in your code.
>
>So, what is this actually saying?:

>
> > #define DLLFUNC(ret) extern __declspec(dllexport) ret __stdcall
>
>It says whenever the preprocessor encounters the text string "DLLFUNC",
>replace it with the defined text. the "(ret)" acts as a parameter,
>saying whatever text appears in parentheses after "DLLFUNC" should be
>inserted whereever "ret" appears in the macro string.
>
>So lets get down to cases, first a step-by-step substitution so you can
>see how that works.
>
> > DLLFUNC(int) SomeDLL_Open();
>
>1. We found DLLFUNC so insert its definition at that location in the source:
>
> extern __declspec(dllexport) ret __stdcall
>
>2. Append the original call
>
> extern __declspec(dllexport) ret __stdcall SomeDLL_Open();
>
>3. Now we passed in "int" as the parameter, so replace any instances of
>"ret" with "int":
>
> extern __declspec(dllexport) int __stdcall SomeDLL_Open();
>
>So, that's what the code looks like at after the first macro pass. Now,
>"__declspec" is a standard C++ macro, read about __declspec here:
>
>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html
>/_core_export_from_a_dll_using___declspec.28.dllexport.29.asp
>
>But given what it does, I don't think you need to worry too much about
>its exact expansion. My first guess at a Delphi translation:
>
> function SomeDLL_Open(): Integer; stdcall; name 'SomeDLL_Open';
>
>This declaration would go in a "Exports" section of your DLL.
>
>Similarly:
>
> > DLLFUNC(void) SomeDLL_Close();
>
> extern __declspec(dllexport) void __stdcall SomeDLL_Close();

>
> > DLLFUNC(int) SomeDLL_GetData(BYTE* pDataType, const PBYTE* pTheData,
> > DWORD* pDataSize);
>
> extern __declspec(dllexport) int __stdcall SomeDLL_GetData(

> BYTE* pDataType, const PBYTE* pTheData, DWORD* pDataSize);
>
> > DLLFUNC(int) SomeDLL_Request(BYTE byRequestType, DWORD dwRequestData);
>
> extern __declspec(dllexport) int __stdcall SomeDLL_Request(
> BYTE byRequestType, DWORD dwRequestData);
>
> > DLLFUNC(int) SomeDLL_GetErrorCondition();
>
> extern __declspec(dllexport) int __stdcall SomeDLL_GetErrorCondition()
>
>HTH

Yes, it sure did--Thanks Stephen. (thanks Maarten, and Eugenijus too!)

What I came up with that compiled is:

// Trashed the macro, and manually constructed the statements...

// C++: DLLFUNC(int) SomeDLL_Open();
Function SomeDLL_Open(): Integer; StdCall;
Exports SomeDLL_Open Name 'SomeDLL_Open';

// Apparently, the 'Exports' keyword can be placed anywhere, so
// why not just after the Function is declared?


// C++: DLLFUNC(void) SomeDLL_Close();
Procedure SomeDLL_Close(); StdCall;
Exports SomeDLL_Close Name 'SomeDLL_Close';

// C++: DLLFUNC(int) SomeDLL_GetData(BYTE* pDataType,
// const PBYTE* pTheData, DWORD* pDataSize);
Function SomeDLL_GetData(pDataType: Byte; const pTheData: PBYTE;
pDataSize: LongInt): Integer; StdCall;
Exports SomeDLL_GetData NAME 'SomeDLL_GetData';

// C++: DLLFUNC(int) SomeDLL_Request(BYTE byRequestType, DWORD
dwRequestData);
Function SomeDLL_Request(byRequestType: Byte; dwRequestData: LongInt):
Integer; StdCall;
Exports SomeDLL_Request NAME 'SomeDLL_Request';

Now I have a few more questions: Even though this format
compiles, will I have any problems with the pointers that
I pretty much ignored in these translations? If so, how
should I alter this code?

Also, Type definitions 1, & 2, below seem to make sense,
but #3 has multiple data types as arguments. And #4 has
that extra parameter, 'BOOL'. What should I do in this
case?

// (1) C++: typedef int (__stdcall *FUNC_OPEN)();
Type FUNC_OPEN = Function(): Integer; StdCall;

// (2) C++: typedef void (__stdcall *FUNC_CLOSE)();
Type FUNC_CLOSE = Function(): Integer; StdCall;

// (3) C++: typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);
Type FUNC_GET = Function({ ???? }): Integer; StdCall;

// (4) C++: typedef void (__stdcall *FUNC_SHOWICON)(BOOL);
Type FUNC_SHOWICON = Procedure(); StdCall;


Thanks for all the light you guys are shining my way!

Maarten Wiltink

unread,
Jan 28, 2005, 1:39:25 PM1/28/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41F9DE...@US-Webmasters.com...
[...]

> // C++: DLLFUNC(int) SomeDLL_Open();
> Function SomeDLL_Open(): Integer; StdCall;
> Exports SomeDLL_Open Name 'SomeDLL_Open';
>
> // Apparently, the 'Exports' keyword can be placed anywhere, so
> // why not just after the Function is declared?

It can? I didn't know that. It seems to be customary to have
all the exports together in the project file. There are things
to be said for both.


[...]


> Now I have a few more questions: Even though this format
> compiles, will I have any problems with the pointers that
> I pretty much ignored in these translations? If so, how
> should I alter this code?

Yes, that's one ugly habit you have. A pointer to something is
something decidedly different from the thing itself. You cannot
treat them as anything close to interchangeable.

If T is a type identifier, ^T is a type for pointers to items
of type T. For many types TX, a corresponding type PX already
exists which is a pointer to TX. The issue is muddied by the
fact the in C, an array is declared as a pointer to the first
element and further elements are accessed through pointer
arithmetic.


> Also, Type definitions 1, & 2, below seem to make sense,
> but #3 has multiple data types as arguments. And #4 has
> that extra parameter, 'BOOL'. What should I do in this
> case?
>
> // (1) C++: typedef int (__stdcall *FUNC_OPEN)();
> Type FUNC_OPEN = Function(): Integer; StdCall;
>
> // (2) C++: typedef void (__stdcall *FUNC_CLOSE)();
> Type FUNC_CLOSE = Function(): Integer; StdCall;
>
> // (3) C++: typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);
> Type FUNC_GET = Function({ ???? }): Integer; StdCall;
>
> // (4) C++: typedef void (__stdcall *FUNC_SHOWICON)(BOOL);
> Type FUNC_SHOWICON = Procedure(); StdCall;

You know what a procedure prototype looks like in Pascal, right?
In C, you're allowed to leave out the parameter names because they
don't need to match anyway. Pascal makes you include formal names
because otherwise it wouldn't look like Pascal or something.

As for "BOOL", see "LongBool".

Groetjes,
Maarten Wiltink


W. D.

unread,
Jan 28, 2005, 5:58:53 PM1/28/05
to
Maarten Wiltink wrote:
>
> "W. D." <NewsG...@US-Webmasters.com> wrote in message
> news:41F9DE...@US-Webmasters.com...
> [...]
> > // C++: DLLFUNC(int) SomeDLL_Open();
> > Function SomeDLL_Open(): Integer; StdCall;
> > Exports SomeDLL_Open Name 'SomeDLL_Open';
> >
> > // Apparently, the 'Exports' keyword can be placed anywhere, so
> > // why not just after the Function is declared?
>
> It can? I didn't know that. It seems to be customary to have
> all the exports together in the project file. There are things
> to be said for both.

Yep. From the help file:

"An exports clause can appear anywhere and any number of
times in the declaration part of a program or library,
or in the interface or implementation section of a unit.
Programs seldom contain an exports clause."


>
> [...]
> > Now I have a few more questions: Even though this format
> > compiles, will I have any problems with the pointers that
> > I pretty much ignored in these translations? If so, how
> > should I alter this code?
>
> Yes, that's one ugly habit you have. A pointer to something is
> something decidedly different from the thing itself. You cannot
> treat them as anything close to interchangeable.

Understood. Delphi is supposed to automatically handle the
pointers in various data types, so I am perplexed when to use
them when C requires manual handling.


>
> If T is a type identifier, ^T is a type for pointers to items
> of type T. For many types TX, a corresponding type PX already
> exists which is a pointer to TX. The issue is muddied by the
> fact the in C, an array is declared as a pointer to the first
> element and further elements are accessed through pointer
> arithmetic.

Exactly. Can anyone 'point' to a cheat sheet on pointer
arithmetic in Delphi?

>
> > Also, Type definitions 1, & 2, below seem to make sense,
> > but #3 has multiple data types as arguments. And #4 has
> > that extra parameter, 'BOOL'. What should I do in this
> > case?
> >
> > // (1) C++: typedef int (__stdcall *FUNC_OPEN)();
> > Type FUNC_OPEN = Function(): Integer; StdCall;
> >
> > // (2) C++: typedef void (__stdcall *FUNC_CLOSE)();
> > Type FUNC_CLOSE = Function(): Integer; StdCall;
> >
> > // (3) C++: typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);
> > Type FUNC_GET = Function({ ???? }): Integer; StdCall;
> >
> > // (4) C++: typedef void (__stdcall *FUNC_SHOWICON)(BOOL);
> > Type FUNC_SHOWICON = Procedure(); StdCall;
>
> You know what a procedure prototype looks like in Pascal, right?
> In C, you're allowed to leave out the parameter names because they
> don't need to match anyway. Pascal makes you include formal names
> because otherwise it wouldn't look like Pascal or something.

Right. That's why I like Pascal--it keeps you out of run-time
trouble.

In these cases, is *ANYTHING* needed inside parentheses, or will
Delphi allow any type of data types?

Also, when there is a parameter at the end, should I just ignore
it as is the case with '(BOOL)'?

>
> As for "BOOL", see "LongBool".

Hmmm. LongBool -- that's a new one for me. I wonder why more
than 1 type of boolean would be needed. I guess just for type
matching. In this conversion, I've just been using 'Boolean'.
According to the Help file a LongBool takes up 4 bytes:

A Boolean variable occupies one byte of memory, a ByteBool
variable also occupies one byte, a WordBool variable
occupies two bytes (one word), and a LongBool variable
occupies four bytes (two words).

It's also interesting that Dr. Bob's HeadConv page shows
'Bool', which doesn't exist in Delphi/Pascal as far as I
know:

http://www.drbob42.com/delphi/headconv.htm


>
> Groetjes,
> Maarten Wiltink

Maarten Wiltink

unread,
Jan 29, 2005, 7:50:27 AM1/29/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:41FAC3...@US-Webmasters.com...

> Maarten Wiltink wrote:
>> "W. D." <NewsG...@US-Webmasters.com> wrote in message
>> news:41F9DE...@US-Webmasters.com...


> [...] From the help file:


>
> "An exports clause can appear anywhere and any number of
> times in the declaration part of a program or library,
> or in the interface or implementation section of a unit.
> Programs seldom contain an exports clause."

Okay. I learned something, too.


>>> Now I have a few more questions: Even though this format
>>> compiles, will I have any problems with the pointers that
>>> I pretty much ignored in these translations? If so, how
>>> should I alter this code?
>>
>> Yes, that's one ugly habit you have. A pointer to something is
>> something decidedly different from the thing itself. You cannot
>> treat them as anything close to interchangeable.
>
> Understood. Delphi is supposed to automatically handle the
> pointers in various data types, so I am perplexed when to use
> them when C requires manual handling.

When you're interfacing with other languages, you can't take
things for granted anymore. You have to get them _right_. Delphi
doesn't much encourage that otherwise, that's true.


> [...] Can anyone 'point' to a cheat sheet on pointer
> arithmetic in Delphi?

There isn't much to it at all. It's exactly the same as in C, really.
Addition to a typed pointer is scaled by the referenced type. Add 1 to
a PChar and the pointer is moved by 1 Char. Add 1 to a PWideChar and
the pointer is moved by 1 WideChar. Add 34 to a ^Widget and the pointer
is moved by 34 Widgets.

Untyped pointers shouldn't be subjected to this. At all. Even if the
compiler doesn't complain. (Looks down) Anyone else for this soapbox?


[...]


> In these cases, is *ANYTHING* needed inside parentheses, or will
> Delphi allow any type of data types?

If you want parameters, put them where you'd expect. The parameters
(their types, if not their names) are an integral part of a procedural
type. Pascal is strongly typed. Draw your own conclusions (or witness
the compilation errors).


> Also, when there is a parameter at the end, should I just ignore
> it as is the case with '(BOOL)'?

You should stop ignoring things.


>> As for "BOOL", see "LongBool".
>
> Hmmm. LongBool -- that's a new one for me. I wonder why more

> than 1 type of boolean would be needed. ...

Exactly for interfacing with other languages.


[...]


> It's also interesting that Dr. Bob's HeadConv page shows
> 'Bool', which doesn't exist in Delphi/Pascal as far as I
> know:
>
> http://www.drbob42.com/delphi/headconv.htm

Bool is declared to be LongBool in the Windows unit.

Groetjes,
Maarten Wiltink


VBDis

unread,
Jan 29, 2005, 9:38:09 PM1/29/05
to
Im Artikel <41FAC3...@US-Webmasters.com>, "W. D."
<NewsG...@US-Webmasters.com> schreibt:

>Exactly. Can anyone 'point' to a cheat sheet on pointer
>arithmetic in Delphi?

Even if direct pointer arithmetic is possible only with PCHAR, Inc and Dec work
for pointers of any type.

DoDi

VBDis

unread,
Jan 29, 2005, 9:38:12 PM1/29/05
to
Im Artikel <41FAC3...@US-Webmasters.com>, "W. D."
<NewsG...@US-Webmasters.com> schreibt:

>> > // (3) C++: typedef int (__stdcall *FUNC_GET)(BYTE*,PBYTE*,DWORD*);


>> > Type FUNC_GET = Function({ ???? }): Integer; StdCall;

???? = 3 arguments of the given types, named as you like.

>> > // (4) C++: typedef void (__stdcall *FUNC_SHOWICON)(BOOL);
>> > Type FUNC_SHOWICON = Procedure(); StdCall;

>Also, when there is a parameter at the end, should I just ignore


>it as is the case with '(BOOL)'?

You cannot omit any parameter. The parentheses at the end contain the parameter
list, possibly reduced to the parameter types (names omitted). The parentheses
before are required by the C syntax for procedure pointers.


>> As for "BOOL", see "LongBool".
>
>Hmmm. LongBool -- that's a new one for me.

It's a Windows API specific type, added to Delphi for convenience. Such
somewhat-boolean types only should be used for the return values (or arguments)
of Windows API functions.

DoDi

Jamie

unread,
Jan 31, 2005, 1:45:03 AM1/31/05
to
you can cast pointers.
DWORD(SomePointer) etc///

Maarten Wiltink

unread,
Jan 31, 2005, 5:03:26 AM1/31/05
to
"Jamie" <jamie_5_not_vali...@charter.net> wrote in message
news:UqhLd.201$0Z6...@fe06.lga...

> VBDis wrote:
>> Im Artikel <41FAC3...@US-Webmasters.com>, "W. D."
>> <NewsG...@US-Webmasters.com> schreibt:

>>> Exactly. Can anyone 'point' to a cheat sheet on pointer
>>> arithmetic in Delphi?
>>
>> Even if direct pointer arithmetic is possible only with PCHAR, Inc
>> and Dec work for pointers of any type.

We must not have the same idea of pointer arithmetic. Can't you add
any number to any typed pointer?


> you can cast pointers.
> DWORD(SomePointer) etc///

Yes. But that loses the whole point. Cast a pointer to a number and
addition reverts to addition of integers. No scaling any more.

Groetjes,
Maarten Wiltink


W. D.

unread,
Feb 2, 2005, 5:59:02 PM2/2/05
to
Maarten Wiltink wrote:
>
> "Jamie" <jamie_5_not_vali...@charter.net> wrote in message
>
> > you can cast pointers.
> > DWORD(SomePointer) etc///
>
> Yes. But that loses the whole point. Cast a pointer to a number and
> addition reverts to addition of integers. No scaling any more.
>
> Groetjes,
> Maarten Wiltink

Thanks, Maarten, Jamie, and Dodi!

Now I have a problem translating a C declaration with pointers:

* ((uint32 *)&DataArry[2]) = SomeFunc(SomeVar);

After studying various sources, including:

http://www.sun.com/971124/cover-linden/cchap.html
http://www.sun.com/971124/cover-linden/decoder.gif
http://www-ccs.ucsd.edu/c/syntax.html

I've translated the line as follows:

The actual data of ((int pointer to) the address of DataArray[2])
takes the value of SomeFunc(SomeVar)

Using my knowledge of Pascal operators, I translate
this into:

^(( (^uint32)@DataArray[2] ) := SomeFunc(SomeVar);

Of course, it doesn't compile! Any comments, hints, etc.????

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Also, I've translated this:

uint8 DataArray[8] = {0x44, 0, 0, 0, 0, 0, 0, 0};

into this:

Var
DataArray: array [1..8] of uint8;

DataArray[8] := ($44, $0, $0, $0, $0, $0, $0, $0); // Doesn't
compile!!!
// DataArray[8] := $44; <-- This does compile.

What's going on here????

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Thanks, guys for all your help!!!!!!

Maarten Wiltink

unread,
Feb 3, 2005, 3:02:25 AM2/3/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:42015B...@US-Webmasters.com...

> [...] I have a problem translating a C declaration with pointers:


>
> * ((uint32 *)&DataArry[2]) = SomeFunc(SomeVar);

> [...] I've translated the line as follows:


>
> The actual data of ((int pointer to) the address of DataArray[2])
> takes the value of SomeFunc(SomeVar)
>
> Using my knowledge of Pascal operators, I translate
> this into:
>
> ^(( (^uint32)@DataArray[2] ) := SomeFunc(SomeVar);
>
> Of course, it doesn't compile! Any comments, hints, etc.????

When writing Pascal, write Pascal. A typecast is written "(T)X" in
C, "T(X)" in Pascal. A dereferencing operation is written "*P" in
C, "P^" in Pascal.

You can never have too many brackets.

Make it "(PInteger(@(DataArray[2])))^ := SomeFunc();" and it should
compile. But the question does suggest itself if DataArray has to
be declared as a byte array. That code writes a 32-bit integer into
it; should it perhaps be an array of integers, or a record?


> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Also, I've translated this:
>
> uint8 DataArray[8] = {0x44, 0, 0, 0, 0, 0, 0, 0};
>
> into this:
>
> Var
> DataArray: array [1..8] of uint8;

In C, array indices run from 0 to N-1.


> DataArray[8] := ($44, $0, $0, $0, $0, $0, $0, $0); // Doesn't
> compile!!!
> // DataArray[8] := $44; <-- This does compile.
>
> What's going on here????

DataArray[8] is one element in the array. It's what square brackets do.
Anyway, you can't initialise an entire array in one statement like
that. In a constant declaration you can, but nowhere else. There are
tricks but for now, just write out the eight statements.

Groetjes,
Maarten Wiltink


Jamie

unread,
Feb 3, 2005, 1:27:14 PM2/3/05
to
W. D. wrote:

> Maarten Wiltink wrote:
>
>>"Jamie" <jamie_5_not_vali...@charter.net> wrote in message
>>
>>
>>>you can cast pointers.
>>> DWORD(SomePointer) etc///
>>
>>Yes. But that loses the whole point. Cast a pointer to a number and
>>addition reverts to addition of integers. No scaling any more.
>>
>>Groetjes,
>>Maarten Wiltink
>
>
> Thanks, Maarten, Jamie, and Dodi!
>
> Now I have a problem translating a C declaration with pointers:
>
> * ((uint32 *)&DataArry[2]) = SomeFunc(SomeVar);
>

With out knowing the type DataArray points to i can only
assume its a byte/char field(maybe).

PDword(@DataArray[2])^ := SomeFunc(SomeVar);

(unit32 *) is a type cast to force the value to the right
(being the address returned) to reflect as pointer to an
unsigned integer, in delphi this would be a DWORD but you
could actually use integer (pinteger) in its place most likely.
@ does the &,PDword does the (uint32) and the ^ does the * (....

i am sure if i have something wrong here i will be corrected. :)
P.S.
if you don't have the PDword type you can do this.
Type
PDword = ^word;
etc.


Jamie

unread,
Feb 3, 2005, 1:28:51 PM2/3/05
to
W. D. wrote:

> Maarten Wiltink wrote:
>
>>"Jamie" <jamie_5_not_vali...@charter.net> wrote in message
>>
>>
>>>you can cast pointers.
>>> DWORD(SomePointer) etc///
>>
>>Yes. But that loses the whole point. Cast a pointer to a number and
>>addition reverts to addition of integers. No scaling any more.
>>
>>Groetjes,
>>Maarten Wiltink
>
>
> Thanks, Maarten, Jamie, and Dodi!
>
> Now I have a problem translating a C declaration with pointers:
>
> * ((uint32 *)&DataArry[2]) = SomeFunc(SomeVar);
>

on that last message i sent, the type should be
Type
PDword = ^Dword; // not word :)

VBDis

unread,
Feb 4, 2005, 10:59:16 PM2/4/05
to
Im Artikel <42015B...@US-Webmasters.com>, "W. D."
<NewsG...@US-Webmasters.com> schreibt:

>Also, I've translated this:


>
> uint8 DataArray[8] = {0x44, 0, 0, 0, 0, 0, 0, 0};
>
>into this:
>
> Var
> DataArray: array [1..8] of uint8;
>
> DataArray[8] := ($44, $0, $0, $0, $0, $0, $0, $0); // Doesn't
>compile!!!

Of course it doesn't compile, because you try to assign 8 bytes to a single
byte DataArray[8].

First correct the array dimension, it should read
Var
DataArray: array [0..7] of uint8;
This is perfectly equivalent to the C DataArray[8], with elements from
DataArray[0] to [7] just like in C.

When the compiler doesn't allow for
DataArray := ($44, $0, $0, $0, $0, $0, $0, $0);
(most probably not allowed, but untested)
then you should use the same construct as in C:
Var
DataArray: array [0..7] of uint8 = (...);
or, when DataArray is a local variable that cannot be initialized statically,
then try to use a preset constant. Now you'll also need an explicit array type:
type TDataArray = array [0..7] of uint8;
const InitArray: TDataArray = (...);
var DataArray: TDataArray;
DataArray := InitArray;
(also untested, may not work)
or
Move(InitArray, DataArray, sizeof(DataArray));

Please note that DataArray and InitArray must have identical types (type
names), not only types that look equal! Pascal is very strict in what types are
assignment compatible, whereas in C it's often sufficient that two data types
have the same number of bytes.

DoDi

VBDis

unread,
Feb 4, 2005, 10:59:18 PM2/4/05
to
Im Artikel <42015B...@US-Webmasters.com>, "W. D."
<NewsG...@US-Webmasters.com> schreibt:

>Now I have a problem translating a C declaration with pointers:


>
> * ((uint32 *)&DataArry[2]) = SomeFunc(SomeVar);

The procedures differ, depending on the size of uint32 and DataArry[2]. In a
first approach the above C code can be rewritten as

uint32(DataArry[2]) := SomeFunc(SomeVar);

When the type sizes differ, the compiler issues an error message. Then the same
way must be taken as in the C code: take the address of the target variable,
convert it into an pointer of the desired type, and assign the value to the
location pointed to. type Puint32 = ^uint32;
...
Puint32(&DataArry[2])^ := SomeFunc(SomeVar);

Please note that now, just as in the C code, the compiler will overwrite as
many bytes as defined for uint32, regardless of the size of DataArry[2]. You
only can hope that this is the desired operation, otherwise the assignment can
overwrite DataArry[3], or whatever resides in memory after DataArry[2].

Unfortunately it cannot always be seen easily when a typecast will result in a
cast, and when it will result in a conversion. An immediate assignment
DataArry[2] := SomeFunc(SomeVar);
may silently convert the result of SomeFunc to the type of DataArry[2] before
the assignment, if such a conversion is both required and allowed. This would
not be the same effect as in the original C code. But often C coders insert too
many typecasts, and wonder afterwards why their code doesn't behave as
expected. One never should try to fool an compiler with typecasts, when the
compiler otherwise doesn't allow some operation. One better should try to
understand what operation really is meant, and then choose a syntactically and
semantically clean construct for that operation. What data type has
DataArry[2]?

Fortunately Delphi allows for typecasts on the left hand side of an assignment
ONLY when the types are equal in size. Then you can be sure that nothing but
the given variable is overwritten by the assignment, and that the variable also
is completely overwritten, not only partially (e.g. first byte of some longer
type).

On the right hand side of an assignment, or in any expression, types of
different sizes can result in a conversion of the value. Every language (even C
;-) specifies what type conversions a compiler can insert silently. When you
have enabled range checks, what's a good idea at least during development, the
assignment of a long value to a shorter variable may result in a range check
(or similar) exception at runtime, when an actual value exceeds the range of
the target type.


> ^(( (^uint32)@DataArray[2] ) := SomeFunc(SomeVar);

Nice try, but you confuse the "^" syntax.
In type declarations "^" is a prefix operator, "^t" means "pointer to t" (C:
t*);
In expressions "^" is a postfix operator, "p^" means "p dereferenced" (C: *x);

In the above line you mix a type declaration (^uint32 is equivalent to C:
uint32*) with a dereferencing operation. A better translation were
^uint32(@...)^ := ..., but AFAIK such a mix is not allowed in Pascal and must
be resolved by an explicit typedef:
type Puint32 = ^uint32;
...
Puint32(@DataArry[2])^ := SomeFunc(SomeVar);

DoDi

Alf Christophersen

unread,
Feb 9, 2005, 6:27:09 PM2/9/05
to
On Wed, 19 Jan 2005 14:57:11 +0100, Bjørge Sæther
<bjorge@haha_itte_dottie_no.no> wrote:

>
>FillChar(TheRecord, SizeOf(TheRecord), 0);

Possibly

FillChar(TheRecord, SizeOf(TheRecord), #0);

is more what was needed.

W. D.

unread,
Feb 21, 2005, 6:17:16 PM2/21/05
to
Hi Folks,

Thanks to all those who have been helping me in this
struggle to convert this C-code to Delphi!

Hopefully, someone has seen this type of 'struct' that
looks like a class:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct _DBFieldName
{
char FieldName[40];
};


struct DBFieldNames
{
uint16 NumFieldNames;
_DBFieldName *Names;

DBFieldNames()
{ Names = NULL; }

~DBFieldNames()
{ delete[] Names; Names = NULL; }
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Is there similar 'Record' syntax that would work,
or should I make this a class, or what????

Thank you so kindly for your assistance!

Nicolai Hansen

unread,
Feb 23, 2005, 3:28:02 AM2/23/05
to
> struct _DBFieldName
> {
> char FieldName[40];
> };
>
>
> struct DBFieldNames
> {
> uint16 NumFieldNames;
> _DBFieldName *Names;
>
> DBFieldNames()
> { Names = NULL; }
>
> ~DBFieldNames()
> { delete[] Names; Names = NULL; }
> };
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

something like

type
TDBFieldName=String[40];
PDBFieldName=^TDBFieldName;

TDBFieldNames=object
Names: PDBFieldName;
constructor Create;
destructor Destroy;
end;

implementation

constructor TDBFieldNames.Create
begin
Names:=nil;
end;

destructor TDBFieldNames.Destroy;
begin
dispose(Names);
Names:=nil;
end;

W. D.

unread,
Feb 23, 2005, 5:35:48 PM2/23/05
to
Thanks, Nicolai, Jonathan, Lennie, Roger, Stephen, & Walter!

I think I'll try it as a class and see if it works. Otherwise
I'll go back and kludge together a record.


Now I have some lines as follows:

#pragma pack (1)

and

#pragma pack()


According to Rudy:

http://rvelthuis.bei.t-online.de/articles/articles-convert.htm#aligns
If alignment is set to 1, no filling will occur at all,
and the sum of the member sizes is the same as the size
of the struct. This is equivalent to a packed record in
Delphi. Note: filler bytes are also inserted after the
last field of a record, to align the next record, for
instance in an array, as well.

Am I correct in assuming that '#pragma pack()' means
to align at 8 bits, with filler bits as needed?

How would these 2 lines differ in Delphi code?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SomePackedRecord = Packed Record

// Record elements...

End; // SomePackedRecord = Packed Record
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Thanks again for your help!!!!!!!

W. D.

unread,
Feb 28, 2005, 5:20:24 PM2/28/05
to NewsG...@us-webmasters.com
Thanks, Jonathan, Roger, Nicolai for your help!

Does anyone know how I can check for the end of
file for a pointer to a FILE?



Type
FilePtr = ^File;

Public
// static void SetFileHandle(FILE *fp) // {my_fp = fp;}
Procedure SetFileHandle(fp: FilePtr);

Private

// The constructors use this file handle to load data from
// C++: static FILE *my_fp;
my_fp: FilePtr;


// C++: if (my_fp)
If (my_fp <> NIL) Then {do stuff} ;


// C++: if (!feof(my_fp))
If (NOT EOF(my_fp)) Then {do stuff} ;

// ^^^ I get an 'Incompatible Types' error here.


Any ideas on how to test for the end of file using
a pointer to a FILE?

Many thanks for any light you can shed!!!!

Maarten Wiltink

unread,
Mar 1, 2005, 2:53:01 AM3/1/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:422399...@US-Webmasters.com...

> Does anyone know how I can check for the end of
> file for a pointer to a FILE?

Dereference it so it becomes a file again, and call Eof() on that.
But why hide it behind a pointer in the first place?

Groetjes,
Maarten Wiltink


W. D.

unread,
Mar 1, 2005, 6:11:31 PM3/1/05
to
Thanks Eddie, Mike, and Maarten!!!

At 16:58 2/28/2005, Eddie Shipman, wrote:
>Would it be?
> if (NOT EOF(my_fp^)) then {do stuff} ;
>
>The ^ at the end should dereference the pointer.

I guess that should have been obvious. It compiles
fine now.

Maarten Wiltink wrote:
> But why hide it behind a pointer in the first place?

Good question. I am trying to duplicate the C++ code,
and that is how it is written. Once I get all the code
converted and compiled, I'll then need to debug everything.
Who knows how much I'll have to change everything around.

Does anyone know the equivalent of C++'s 'Delete[]' in
Delphi?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// C++: char *RawData;
RawData: PChar;

// C++: FieldTyypes *The_Fields;
The_Fields: FieldTyypesPtr;


// C++: SOMEDB::~SOMEDB()
Destructor SOMEDB.Destroy;

// C++: {
Begin

delete[] RawData;
delete[] The_Fields;

// C++: }
End; // Destructor SOMEDB.Destroy;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Maarten Wiltink

unread,
Mar 2, 2005, 3:59:01 AM3/2/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:4224F6...@US-Webmasters.com...
> Maarten Wiltink wrote:

>> But why hide it behind a pointer in the first place?
>
> Good question. I am trying to duplicate the C++ code,
> and that is how it is written.

C does not have var parameters. So when you need one, you
pass a pointer to your variable. You'll notice that all
the traditional-style I/O functions in Pascal (WriteLn for
example) pass the file variable by reference.


[...]


> Does anyone know the equivalent of C++'s 'Delete[]' in
> Delphi?
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> // C++: char *RawData;
> RawData: PChar;
>
> // C++: FieldTyypes *The_Fields;
> The_Fields: FieldTyypesPtr;
>
>
> // C++: SOMEDB::~SOMEDB()
> Destructor SOMEDB.Destroy;
>
> // C++: {
> Begin
>
> delete[] RawData;
> delete[] The_Fields;
>
> // C++: }
> End; // Destructor SOMEDB.Destroy;
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It looks like an array deallocator. If you translated these things into
dynamic arrays, letting the references go out of scope should be enough.
If you want to be explicit about it, SetLength() them to zero elements.
(Personally, I don't like setting things that aren't pointers to nil,
and arrays aren't pointers in the language even if they are in an
implementation.)

A dynamic array of Char is of course a (long) string and may be handled
in the same way, although I would intuitively clear a dynamic array in
a destructor but never a string. The name RawData on the other hand,
suggest that it should really have been an opaque buffer of _bytes_,
not characters.

Groetjes,
Maarten Wiltink


Rudy Velthuis

unread,
Mar 3, 2005, 4:24:52 PM3/3/05
to
Maarten Wiltink wrote:

> C does not have var parameters. So when you need one, you
> pass a pointer to your variable.

Actually, I think current C has. But headers are of course compatible
with older C versions as well.
--
Rudy Velthuis http://rvelthuis.bei.t-online.de

"I believe that sex is a beautiful thing between two people. Between
five, it's fantastic." -- Woody Allen

Maarten Wiltink

unread,
Mar 4, 2005, 3:38:26 AM3/4/05
to
"Rudy Velthuis" <rvel...@gmx.de> wrote in message
news:xn0dzbqqh5vcqaq...@www.teamb.com...
> Maarten Wiltink wrote:

>> C does not have var parameters. So when you need one, you
>> pass a pointer to your variable.
>
> Actually, I think current C has. But headers are of course
> compatible with older C versions as well.

Ah yes, that rings a bell. Something about the latest C (C++?)
standard thinking two kinds of pointers weren't enough and
adding a third.

Groetjes,
Maarten Wiltink


Rudy Velthuis

unread,
Mar 4, 2005, 7:06:27 AM3/4/05
to
Maarten Wiltink wrote:

Two kinds? Oh, you mean arrays and plain pointers? Now they have
references as well, IIRC. C++ most certainly has them.

"The only thing necessary for the triumph of evil is for good men to do
nothing."
-- Edmund Burke (1729-1797)

Maarten Wiltink

unread,
Mar 4, 2005, 3:01:16 PM3/4/05
to
"Rudy Velthuis" <rvel...@gmx.de> wrote in message
news:xn0dzcqml6quifq...@www.teamb.com...
> Maarten Wiltink wrote:

>> Ah yes, that rings a bell. Something about the latest C (C++?)
>> standard thinking two kinds of pointers weren't enough and
>> adding a third.
>
> Two kinds? Oh, you mean arrays and plain pointers? Now they have
> references as well, IIRC. C++ most certainly has them.

No, worse than that. Pointers and references were the two types I
had in mind. The upcoming 2005 ECMA (2006 ISO/IEC) C++ standard
includes .Net support which segregates out pointers into the
garbage-collected heap, now called "handles" and declared with ^
instead of *... but dereferenced with * like the old pointers.
This is a compatibility feature so code using either old or new
pointers can be generic.

Groetjes,
Maarten Wiltink


W. D.

unread,
Mar 4, 2005, 7:21:35 PM3/4/05
to

Hmmm. I set them to NIL and it compiled. We'll see if it runs--
eventually.

W. D.

unread,
Mar 4, 2005, 7:21:47 PM3/4/05
to
Arrrrrgh! Pointers were invented by Satan!

These appear to be pointers to functions. I can't seem to find
many examples of Delphi 'method pointers'. Do any of you
have an idea of what would be appropriate?

typedef void (*ProcessPkt)(const DlPkt *p);

typedef bool (*DL_Msg)(uint32 CurPktCnt, uint32 BytsRcvd, uint32
TtlExptd, const DlPkt *p);

typedef bool (*DLabortSgnl)(bool BfrAbort);

void SetDlCommMsg(ProcessPkt FunctionPtr);


Thanks dudes, for your previous answers and any help you can
provide on this one!

Ioannis Vranos

unread,
Mar 4, 2005, 7:29:23 PM3/4/05
to
W. D. wrote:


Do not get upset with that, but what you are trying to do is convert
from a powerful language to one less powerful, and you can't do that in
a straightforward way (while the opposite can be done). Unavoidably you
will have to change many things in the code to imitate around how things
are being done in the code, so as to complete the conversion.


I do not remember much of C++Builder, but if Delphi and C++Builder can
create compatible dlls among them, then you may encapsulate the C++ code
in a dll under one or more classes or functions, and use that dll in
your Delphi code.

--
Ioannis Vranos

http://www23.brinkster.com/noicys

Ioannis Vranos

unread,
Mar 4, 2005, 7:37:05 PM3/4/05
to
Maarten Wiltink wrote:

> No, worse than that. Pointers and references were the two types I
> had in mind. The upcoming 2005 ECMA (2006 ISO/IEC) C++ standard


Actually it is C++/CLI, a standard of *extensions* to ISO C++ to take
advantage of a CLI machine where one is available.

> includes .Net support which segregates out pointers into the
> garbage-collected heap, now called "handles" and declared with ^
> instead of *... but dereferenced with * like the old pointers.
> This is a compatibility feature so code using either old or new
> pointers can be generic.


At first, with the arrival of VC++ 2005 and C++/CLI standard, C++
becomes the systems programming language of .NET.


Take a look at these:


http://msdn.microsoft.com/msdnmag/issues/05/01/COptimizations/default.aspx

http://pluralsight.com/blogs/hsutter/archive/2004/10/05/2672.aspx

http://blogs.msdn.com/branbray/archive/2003/11/07/51007.aspx

http://www.accu.org/conference/presentations/Sutter_-_Is_C++_Relevant_on_Modern_Environments_%28keynote%29.pdf


And a page of mine:

http://www23.brinkster.com/noicys/cppcli.htm

Now some more on this:

With C++/CLI, C++ has two worlds: The unmanaged world and the managed world.

In the managed world every CLI (.NET) feature is provided separately
from the unmanaged world features.

Maarten Wiltink

unread,
Mar 5, 2005, 5:52:54 AM3/5/05
to
"Ioannis Vranos" <i...@remove.this.grad.com> wrote in message
news:1109982565.35631@athnrd02...
> W. D. wrote:

>> These appear to be pointers to functions. I can't seem to find
>> many examples of Delphi 'method pointers'. Do any of you
>> have an idea of what would be appropriate?

Reading the help is always appropriate. Watch out for the difference
between regular procedures and methods.


>> typedef void (*ProcessPkt)(const DlPkt *p);
>>
>> typedef bool (*DL_Msg)(uint32 CurPktCnt, uint32 BytsRcvd, uint32
>> TtlExptd, const DlPkt *p);
>>
>> typedef bool (*DLabortSgnl)(bool BfrAbort);
>>
>> void SetDlCommMsg(ProcessPkt FunctionPtr);

type
ProcessPkt = procedure(var p: DlPkt);
DL_Msg = function(Cardinal CurPktCnt; Cardinal BytsRcvd;
Cardinal TtlExptd; var p: DlPkt): Boolean;
DLabortSgnl = function(BfrAbort: Boolean): Boolean;

procedure SetDlCommMsg(FunctionPtr: ProcessPkt); forward;

There may be a cdecl or two missing in there if you want to interface
directly with compiled C code.


> Do not get upset with that, but what you are trying to do is convert
> from a powerful language to one less powerful,

Bollocks. Procedural types are _exactly_ as powerful in either language.

Groetjes,
Maarten Wiltink


Jamie

unread,
Mar 5, 2005, 4:23:08 PM3/5/05
to
W. D. wrote:

your making it hard on your self.

here are some tips
a procedure in delphi can be past to as a reference via the
@ infront of the procedure. kind in mind that you should be using
the calling convention that is expected, for example a "STDCALL" tagged
at the end of the procedure header/
etc..
if you really want to have procedure pointers., you can do this.
var
myprocedurename:procedure(the params):stdcall; // if needed ..

some where in your code you simply set it from an address.
etc...
this is just some insight for you.

Bruce Roberts

unread,
Mar 7, 2005, 12:45:11 PM3/7/05
to

"Ioannis Vranos" <i...@remove.this.grad.com> wrote in message
news:1109982565.35631@athnrd02...

> Do not get upset with that, but what you are trying to do is convert


> from a powerful language to one less powerful, and you can't do that in
> a straightforward way (while the opposite can be done). Unavoidably you
> will have to change many things in the code to imitate around how things
> are being done in the code, so as to complete the conversion.

I have to quibble with your characterization of C as a more powerful
language than Delphi. If one were to try and translate a complex assembly
language program to C, I presume that you would characterize assembly as
"more powerful"?

Its not a question of how "powerful" a language is or isn't. Especially
since "powerful" is a subjective term with no consensus as to what it means.
Certainly not how it can be measured.

When translating between any two languages, but especially two that do not
share a common cultural background, one can have difficulty. One will always
find things expressible in one that have no real translation into the other.
It doesn't matter if one is translating natural or formal languages. The
culture in and represented by a language makes a real difference.


Maarten Wiltink

unread,
Mar 8, 2005, 7:44:27 AM3/8/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:422CDF...@US-Webmasters.com...
[...]
> I now seem to be getting an error when comparing the
> difference of 2 pointer addresses:
>
> "Operator not applicable to this operand"

The help (for "pointer operators") suggests you can only subtract
PChars.


> Here is some code:

<snip>

> In the above C code, does '82' mean decimal 82? Is there
> some other way this number should be written?

0x82 = hexadecimal 82, 130 decimal
082 = octal 82, 66 decimal
82 = decimal 82

Delphi has $82 for hex and no equivalent for octal.


[...]
> Also, is this kludgy code the proper way to index
> pointers?

Indexing pointers is not problematic. P[i] = (P+i)^, and @P[i] is P+i
(and the latter should be written P+i, IMO).

Groetjes,
Maarten Wiltink


Jamie

unread,
Mar 8, 2005, 5:52:33 PM3/8/05
to
W. D. wrote:

>
> Here is some code:
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Type
>
> ByteArray = Array [0..$0FFFFFFF] of Byte;
> ByteArrayPtr = ^ByteArray;
>
> uint8Array = Array [0..$0FFFFFFF] of uint8;
> uint8ArrayPtr = ^uint8Array;
>
> uint8Ptr = ^uint8;
>
>
> Var
>
> ByteAryPtr: ByteArrayPtr;
> uint8AryPtr: uint8ArrayPtr
>
> cp: uint8Ptr;
>
>
> // C++: uint8 *cp = &ThePort->Pkt.data[16]; // 'ThePort' is a class
> pointer
> uint8AryPtr := Pointer(@ThePort.Pkt.data);
> cp := uint8Ptr(uint8AryPtr[16]);
>
> ByteAryPtr := Pointer(@ThePort.Pkt.data);
>
> // C++: while (*cp != 0x1A && cp - (&ThePort->Pkt.data[16]) < 82)
> While (
> (cp^ <> $1A)
> AND
> ( (cp - (@ByteAryPtr[16])) < 82 ) // <-- "Operator not
> applicable to this operand"
> ) Do
>
> Begin
> // Do stuff
> End;
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


>
> In the above C code, does '82' mean decimal 82? Is there

> some other way this number should be written? It would
> seem to me to be legal to determine the difference between
> to addresses.
i would like the see the original code, i think really have it messed up.
any ways, you can use inc/dec on typed pointers., it will increment the
pointer in the correct range to match the type size.
for example.
if the pointer was an integer (4 bytes), the pointer would have 4
added to it when you do a inc(integerPointer, 1);
in your problem line above, you could case the whole statement into
integers to perform the math.
if Pbyte(dword(cp)-dword(@byteAryptr[16]))^ < 82 then ...
that may give you some insight.

Nicolai Hansen

unread,
Mar 9, 2005, 3:48:19 AM3/9/05
to
"Maarten Wiltink" <maa...@kittensandcats.net> wrote in message news:<42281e9b$0$28982$e4fe...@news.xs4all.nl>...

C# has an "out" keyword or something for this doesn't it? I don't
recall seeing it in C++ though.

Maarten Wiltink

unread,
Mar 9, 2005, 4:34:22 AM3/9/05
to
"Nicolai Hansen" <n...@aub.dk> wrote in message
news:d96764ff.0503...@posting.google.com...

> "Maarten Wiltink" <maa...@kittensandcats.net> wrote in message
news:<42281e9b$0$28982$e4fe...@news.xs4all.nl>...
>> "Rudy Velthuis" <rvel...@gmx.de> wrote in message
>> news:xn0dzbqqh5vcqaq...@www.teamb.com...
>>> Maarten Wiltink wrote:

>>>> C does not have var parameters. So when you need one, you
>>>> pass a pointer to your variable.
>>>
>>> Actually, I think current C has. But headers are of course
>>> compatible with older C versions as well.
>>
>> Ah yes, that rings a bell. Something about the latest C (C++?)
>> standard thinking two kinds of pointers weren't enough and
>> adding a third.

> C# has an "out" keyword or something for this doesn't it? I don't


> recall seeing it in C++ though.

C# has really very little to do with C/C++. In hiding pointers from
the user, it's (unsurprisingly) much more like Pascal.

There are "ref" and "out" modifiers on parameters in C#. The only
difference with "var" and "out" in Delphi is that you have to
repeat them in the function _call_.

Groetjes,
Maarten Wiltink


W. D.

unread,
Mar 11, 2005, 2:28:44 AM3/11/05
to
Thanks Maarten, Stephen, Jamie & Cosmind for your help!!!

I am now getting an "Incompatible Types" error when assigning
an instance of a class to a pointer. I am using the
Constructor as recommended but I still don't understand why
I am getting error. Any clues available?


// C++: ClassPtr = new (ComClass_Serial(port, baudrate, rx_size,
tx_size));

ClassPtr := ComClass_Serial.Create(port, baudrate, rx_size, tx_size);

Maarten Wiltink

unread,
Mar 11, 2005, 4:22:31 AM3/11/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:423148...@US-Webmasters.com...

> I am now getting an "Incompatible Types" error when assigning
> an instance of a class to a pointer. I am using the
> Constructor as recommended but I still don't understand why
> I am getting error. Any clues available?
>
>
> // C++: ClassPtr = new (ComClass_Serial(port, baudrate, rx_size,
> tx_size));
>
> ClassPtr := ComClass_Serial.Create(port, baudrate, rx_size, tx_size);

Please ask better questions. Show us the delcaration of ClassPtr, the
declaration of ComClass_Serial.Create, the exact error message, and
the point where the compiler reports it.

Object Pascal is a strongly typed language. Any errors against the
typing system should be fairly obvious.

Groetjes,
Maarten Wiltink


Jamie

unread,
Mar 12, 2005, 2:30:06 PM3/12/05
to
W. D. wrote:

declare the class pointer as.

Var
ClassPtr:TComClass_Serial;

classes are already pointers of their own type.

Give it some meaningful name.

W. D.

unread,
Mar 30, 2005, 3:22:28 AM3/30/05
to
Hi Folks,

Many thanks for all the help you have provided!!

Currently, I am getting several of these errors:

'Unsatisfied forward or external declaration'

They occur in the Interface section, even though several
versions of these Overloaded functions are in the
Implementation section (and otherwise compile OK).

One would think that if they exist in the Implematation
section, and they didn't match the templates in the
Interface section, there would be some sort of
mismatch error. But for some reason, the compiler
doesn't think they exist.

I've gotten this type of error when the functions were
owned by a Class. The solution is to prepend the
name of the class onto the function:

TheFunction();

becomes:

TheClassName.TheFunction();


Since these functions aren't contained in a class, what
could be preventing the compiler from finding them?


Again, many thanks for any hints you can provide!

Maarten Wiltink

unread,
Mar 30, 2005, 4:22:29 AM3/30/05
to
"W. D." <Google...@US-Webmasters.com> wrote in message
news:1112170948.3...@o13g2000cwo.googlegroups.com...

> Currently, I am getting several of these errors:
>
> 'Unsatisfied forward or external declaration'
>
> They occur in the Interface section, even though several
> versions of these Overloaded functions are in the
> Implementation section (and otherwise compile OK).
>
> One would think that if they exist in the Implematation
> section, and they didn't match the templates in the
> Interface section, there would be some sort of
> mismatch error. But for some reason, the compiler
> doesn't think they exist.

Overloading makes this harder for the compiler.


> I've gotten this type of error when the functions were
> owned by a Class. The solution is to prepend the
> name of the class onto the function:
>
> TheFunction();
>
> becomes:
>
> TheClassName.TheFunction();
>
>
> Since these functions aren't contained in a class, what
> could be preventing the compiler from finding them?

Hard to say without seeing code. Stripped-down code, please.
Ten to one you'll find the error you made before ever posting.

The ground rule is quite simple. "The compiler is always right."

Groetjes,
Maarten Wiltink


Jamie

unread,
Mar 30, 2005, 11:46:35 AM3/30/05
to
W. D. wrote:

I don't understand what your saying, you state they are
in the interface and implementation section but you can only
access them via a Class name space?
is it possible your trying to expose some members of a
class into the interface section?, if so that can not be
done.

W. D.

unread,
Apr 4, 2005, 4:41:48 PM4/4/05
to
Thanks Maarten, Walter, and Jamie.

The solution to my 'Unsatisfied forward or external declaration'
error was that there were slight differences in the integer
types in the different declarations. To find this out, I
copied the declarations into a text editor--Interface on
top, Implementation on the bottom--then compared the two.
The type differences then were apparent.

I am still struggling with pointers and indexing them. The
current code I am trying to convert is contained in
some nested FOR loops:

===============================================================
A_RecordPtr: ^SomeRecordType;
i: uint32;
j: uint32;
pAuthDB: ^SomeOtherRecordType;


if
(A_RecordPtr[i].SomeBoolFunc(TransposeByteOrder(*(uint32*)&pAuthDB[j].DBID)))
===============================================================

How can I handle this without getting the dreaded
"Array Type Required" error?

Many thanks for your insight!!!!!!!!

Maarten Wiltink

unread,
Apr 4, 2005, 5:06:26 PM4/4/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:4251A6...@US-Webmasters.com...
[...]

> A_RecordPtr: ^SomeRecordType;
> i: uint32;
> j: uint32;
> pAuthDB: ^SomeOtherRecordType;

> if (A_RecordPtr[i].SomeBoolFunc
(TransposeByteOrder
(*(uint32*)&pAuthDB[j].DBID
)
)
)

> How can I handle this without getting the dreaded
> "Array Type Required" error?

By using enough temporary variables, mostly. You should by now have
seen all the errors before and know how to solve any of them. All
that can go wrong now is that you don't spot what exactly is wrong;
the solution to that is to split up the code until you can only make
once mistake at a time.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 14, 2005, 12:25:52 AM4/14/05
to Maarten Wiltink
Thanks Maarten and Moz for your help!!!

This is what I wrote last time:

-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-


I am still struggling with pointers and indexing them. The
current code I am trying to convert is contained in
some nested FOR loops:

===============================================================


A_RecordPtr: ^SomeRecordType;
i: uint32;
j: uint32;
pAuthDB: ^SomeOtherRecordType;


if
(A_RecordPtr[i].SomeBoolFunc(TransposeByteOrder(*(uint32*)&pAuthDB[j].DBID)))

===============================================================

How can I handle this without getting the dreaded
"Array Type Required" error?

-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-

However, it's not just a RECORD that I am trying to
operate on. Rather, there's a CLASS too. I should have
written:

-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-
I am still struggling with pointers to classes and records
(and how to index them). The current code I am trying to

convert is contained in some nested FOR loops:

===============================================================
A_ClassPtr: ^SomeClassType;
i: uint32;
j: uint32;
pAuthDB: ^SomeRecordType;


if
(A_ClassPtr[i].SomeBoolFunc(TransposeByteOrder(*(uint32*)&pAuthDB[j].DBID)))
===============================================================

How can I handle this without getting the dreaded
"Array Type Required" error?
-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-

Maarten Wiltink wrote:
> By using enough temporary variables, mostly. You should by now have
> seen all the errors before and know how to solve any of them.

I wish. With all the pointers, records, classes & indexes, the
levels of abstraction are almost too much for my brain to handle!


> All
> that can go wrong now is that you don't spot what exactly is wrong;
> the solution to that is to split up the code until you can only make

> one mistake at a time.

This makes perfect sense. I just wish I could get a handle on
all the indexing pointers to records/classes. Then I could
split off the other stuff into temporary variables, etc.

>
> Groetjes,
> Maarten Wiltink


At 15:55 4/4/2005, Moz, wrote:
>By declaring a type foo:array of SomeRecordType, and assigning the
>start of the array to it.

Which 'it'? Would that mean something like:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Type
SomeRecTypeAry: Array of SomeRecordType;

@SomeRecTypeAry := pAuthDB;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

>C treats pointers and arrays as identical,
>but Pascal doesn't (it's more strongly typed as well as less case
>sensitive).
>
>Moz

Thanks again guys for your valuable advice. If you would
be so kind, please *point* me in the right direction
once more!

Maarten Wiltink

unread,
Apr 14, 2005, 4:10:58 AM4/14/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:425DF0...@US-Webmasters.com...
[...]

> Maarten Wiltink wrote:
>> By using enough temporary variables, mostly. You should by now have
>> seen all the errors before and know how to solve any of them.
>
> I wish. With all the pointers, records, classes & indexes, the
> levels of abstraction are almost too much for my brain to handle!

So you are in over your head. That's okay, happens to all of us.
Just deal with it in the right way. Trying to understand two levels
at once isn't. Look at the trees first. When you grok the trees,
continue to the forest.


>> All that can go wrong now is that you don't spot what exactly is
>> wrong; the solution to that is to split up the code until you can
>> only make one mistake at a time.
>
> This makes perfect sense. I just wish I could get a handle on
> all the indexing pointers to records/classes. Then I could
> split off the other stuff into temporary variables, etc.

No, you can do that *now*, and it should give you a handle on the
hard parts, because you then have only one hard part per statement.

Start with lifting out the innermost expressions. It's a lexical
operation, no understanding required. Repeat until you start to see
what happens.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 14, 2005, 9:35:21 AM4/14/05
to

Thanks, Maarten for your reply.

The problem is, I don't know how to index the CLASS and RECORD
variables. These are the 'innermost expressions', yes?

A_ClassPtr[i].SomeBoolFunc
pAuthDB[j].DBID

You say I can index them, but my hands just scratch my head
and don't type anything useful. I've tried all sorts
of variations, but the compiler just comes up with its
corresponding variety of error messages.

I've hunted throughout the 'Net, (Web pages and UseNet).
Here are some of my favorites that haven't helped:

http://tinyurl.com/6teew
http://tinyurl.com/3vpu6
http://tinyurl.com/6swdg
http://tinyurl.com/4v53k

While I know how to index pointers by creating a
kludgy array, I don't know how to index CLASSES or
RECORDS. Those pesky methods don't seem to play
nice with my array technique.

Purty please, with sugar on top, may I have a
hint? ;^)

>
> Groetjes,
> Maarten Wiltink

Maarten Wiltink

unread,
Apr 14, 2005, 11:54:25 AM4/14/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:425E71...@US-Webmasters.com...
> Maarten Wiltink wrote:
[...]

>> Start with lifting out the innermost expressions. It's a lexical
>> operation, no understanding required. Repeat until you start to see
>> what happens.

> The problem is, I don't know how to index the CLASS and RECORD


> variables. These are the 'innermost expressions', yes?

I'm not talking about indexing at this point, but only about moving
subexpressions into temporary variables.

However, you can't index classtype references or record type
values in Delphi. You must have an array of them. C arrays look
different. Are you sure you don't have an array? Are you sure
you _shouldn't_ have an array?


> A_ClassPtr[i].SomeBoolFunc
> pAuthDB[j].DBID
>
> You say I can index them, but my hands just scratch my head
> and don't type anything useful. I've tried all sorts
> of variations, but the compiler just comes up with its
> corresponding variety of error messages.


if (A_ClassPtr[i].SomeBoolFunc


(TransposeByteOrder
(*(uint32*)&pAuthDB[j].DBID
)
)
)

The former of your expressions is an outermost, but the other one is
spot on. Leaving the DBID member's type unstated, the above transforms
to:

var Data: T;

Data:=pAuthDB[j].DBID;
if (A_ClassPtr[i].SomeBoolFunc(*(uint *)&Data);

where of course *X is written X^ in Pascal, (uint *) is written PCardinal
where PCardinal = ^Cardinal, and &X @X, so the argument to SomeBoolFunc
becomes (PCardinal(@Data))^. (You never have too many brackets.)

Note that if T is smaller than four bytes, the above code is broken
because the adjacent data aren't duplicated and the code depends on them;
this may well be the entire point of that useless-looking cast.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 23, 2005, 4:19:09 PM4/23/05
to
Again, thanks a bunch, Maarten!

Maarten Wiltink wrote:
>
> "W. D." <NewsG...@US-Webmasters.com> wrote in message
> news:425E71...@US-Webmasters.com...
> > Maarten Wiltink wrote:
> [...]
> >> Start with lifting out the innermost expressions. It's a lexical
> >> operation, no understanding required. Repeat until you start to see
> >> what happens.
>
> > The problem is, I don't know how to index the CLASS and RECORD
> > variables. These are the 'innermost expressions', yes?
>
> I'm not talking about indexing at this point, but only about moving
> subexpressions into temporary variables.
>
> However, you can't index classtype references or record type
> values in Delphi. You must have an array of them.

This is the critical information that I needed. Apparently,
in C++, indexing pointer variables (whether they are strings,
records, classes, or whatever) is just a matter of tacking
on an index:

SomeComplicatedRecord[i].SomeMethod


>C arrays look
> different. Are you sure you don't have an array? Are you sure
> you _shouldn't_ have an array?

I guess I really *SHOULD* have an array in Delphi. Otherwise,
how can I cycle through each member?

This requires converting the type from a pointer to a non-pointer
type. And of course, much of the code that references the
variable will also need to be rewritten.

I've begun to do this but, am wondering how to
deallocate the memory for an Array of Record.
This record, 'Was_a_pointer', is declared in the
'Private' section of a class. In the Destructor,
this is how it was deallocated:

// C++: delete[] Was_a_pointer;


When I try to deallocate this array, I get
all sorts of errors. None of the following
work:

Was_a_pointer := NIL;
FreeMem(Was_a_pointer);
@Was_a_pointer := NIL;
Was_a_pointer.Free;
Dispose(Was_a_pointer);

Is an array that is declared in a class automatically
disposed of when the class is destroyed? If not,
what is the proper way to free memory allocated to
arrays of records?

Thanks soooo much for all your wisdom and insights!

Maarten Wiltink

unread,
Apr 24, 2005, 7:08:49 AM4/24/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:426AAD...@US-Webmasters.com...
> Maarten Wiltink wrote:
[...]

>> However, you can't index classtype references or record type
>> values in Delphi. You must have an array of them.
>
> This is the critical information that I needed. Apparently,
> in C++, indexing pointer variables (whether they are strings,
> records, classes, or whatever) is just a matter of tacking
> on an index:
>
> SomeComplicatedRecord[i].SomeMethod

It is. Frankly, I was labouring under the assumption that you had
discovered this long ago.

In C, a[i] is syntactic sugar for *(a+i). Array indexing borrows from
pointer arithmetic and it is defined that addition to a typed pointer
is scaled by the size of the referenced type. Look again at the
expression *(a+i) and you see that indexing a pointer to the base of
an array of, say, uint32's (four bytes in size), works exactly as you
might expect. Unsurprisingly, an array variable is treated as a pointer
to the base of the array. It works nicely for dynamically allocated
arrays, too, but they are explicitly pointers.

In Pascal, this doesn't work. Arrays are a first-class datatype (well,
almost) and not compatible in any way with pointers to anything. The
single exception is PChar, which is allowed to be indexed in this way,
but that's a C compatiblity feature. The usage of PChar instead of real
strings is a C compatibility feature to begin with.

> [... I] am wondering how to


> deallocate the memory for an Array of Record.
> This record, 'Was_a_pointer', is declared in the
> 'Private' section of a class. In the Destructor,
> this is how it was deallocated:
>
> // C++: delete[] Was_a_pointer;
>
>
> When I try to deallocate this array, I get
> all sorts of errors. None of the following
> work:
>
> Was_a_pointer := NIL;
> FreeMem(Was_a_pointer);
> @Was_a_pointer := NIL;
> Was_a_pointer.Free;
> Dispose(Was_a_pointer);
>
> Is an array that is declared in a class automatically
> disposed of when the class is destroyed? If not,
> what is the proper way to free memory allocated to
> arrays of records?

There are - in Object Pascal - two kinds of arrays. Static arrays
are statically allocated and go away with the containing object.
Dynamic arrays should be SetLength'd to zero elements if you want
to be explicit, but they are also handled by compiler magic if a
containing object is freed.

Setting a dynamic array variable to nil is allowed as a special
case for rather dubious reasons; it is equivalent to SetLength(., 0).
FreeMem should be paired with GetMem. Trying to move the physical
location where a variable lives obviously can't work. Free applies
to objects and dynamic arrays aren't. Dispose should be paired with
New.

All that applies to dynamic arrays. That setting it to nil doesn't
work indicates you had a static array. You don't need to deallocate
those; just let them go out of scope.


> Thanks soooo much for all your wisdom and insights!

Here's one you may not like so much: translating well requires knowing
_both_ languages well. Imagine translating a good book full of inside
jokes, wordplay, and cultural references, from a language you only
half understand. You'll miss some of the words, and everything that is
behind the words.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 24, 2005, 11:56:27 PM4/24/05
to
Maarten Wiltink wrote:

<SNIP>


> There are - in Object Pascal - two kinds of arrays. Static arrays
> are statically allocated and go away with the containing object.
> Dynamic arrays should be SetLength'd to zero elements if you want
> to be explicit, but they are also handled by compiler magic if a
> containing object is freed.
>
> Setting a dynamic array variable to nil is allowed as a special
> case for rather dubious reasons; it is equivalent to SetLength(., 0).
> FreeMem should be paired with GetMem. Trying to move the physical
> location where a variable lives obviously can't work. Free applies
> to objects and dynamic arrays aren't. Dispose should be paired with
> New.
>
> All that applies to dynamic arrays. That setting it to nil doesn't
> work indicates you had a static array. You don't need to deallocate
> those; just let them go out of scope.

So, my Array of Records will be automatically
deallocated when the class that uses it is destroyed?



> > Thanks soooo much for all your wisdom and insights!
>
> Here's one you may not like so much: translating well requires knowing
> _both_ languages well. Imagine translating a good book full of inside
> jokes, wordplay, and cultural references, from a language you only
> half understand. You'll miss some of the words, and everything that is
> behind the words.

No wonder I am having so much trouble. ;^)

Maarten Wiltink

unread,
Apr 25, 2005, 2:53:52 AM4/25/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:426C6A...@US-Webmasters.com...
> Maarten Wiltink wrote:

[...]


> So, my Array of Records will be automatically
> deallocated when the class that uses it is destroyed?

Yes. But be precise. The syntax "array of record" can appear in
program code, and declares a dynamic array variable. The above
bit is about static arrays, which have an ordinal type appearing
in square brackets between "array" and "of". That doesn't change
the fact of its automatic deallocation when a containing
*object* - again, be precise - is freed, but this sort of
confusion is setting yourself up for problems. Compilers are
unforgiving.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 25, 2005, 12:23:34 PM4/25/05
to

OK. To be precise and clear, would the following
be correct?

Array Type Example Dealloc by:
1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
Program
3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
0);
4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
0);

Maarten Wiltink

unread,
Apr 25, 2005, 3:38:18 PM4/25/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:426D19...@US-Webmasters.com...
> Maarten Wiltink wrote:

<applied pedantry>

> OK. To be precise and clear, would the following
> be correct?
>
> Array Type Example Dealloc by:
> 1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
> 2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
> Program
> 3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
> 0);
> 4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
> 0);

Apart from using the word "class" where you mean "object", and me using
"object" where a Borland Greater Pedant would use "class type instance"
or something to differentiate old-style from new-style objects, yes.

It's not complete, though - A3 is also freed when its containing object
is, and that will probably happen more often. In my experience, it's
rare to re-allocate dynamic arrays.

As a final note which I encourage everybody not to read, you can set a
dynamic array reference to nil for the same effect as SetLength'ing it
to zero elements. But that is an ugly hack misguidedly prompted by
implementation issues.

Groetjes,
Maarten Wiltink


W. D.

unread,
Apr 26, 2005, 1:14:08 AM4/26/05
to
Maarten Wiltink wrote:
>
> "W. D." <NewsG...@US-Webmasters.com> wrote in message
> news:426D19...@US-Webmasters.com...
> > Maarten Wiltink wrote:
>
> <applied pedantry>
>
> > OK. To be precise and clear, would the following
> > be correct?
> >
> > Array Type Example Dealloc by:
> > 1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
> > 2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
> > Program
> > 3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
> > 0);
> > 4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
> > 0);
>
> Apart from using the word "class" where you mean "object", and me using
> "object" where a Borland Greater Pedant would use "class type instance"
> or something to differentiate old-style from new-style objects, yes.
>
> It's not complete, though - A3 is also freed when its containing object
> is, and that will probably happen more often. In my experience, it's

^^^destroyed?

Does 'destroyed' go here?

> rare to re-allocate dynamic arrays.
>
> As a final note which I encourage everybody not to read, you can set a
> dynamic array reference to nil for the same effect as SetLength'ing it
> to zero elements. But that is an ugly hack misguidedly prompted by
> implementation issues.

What would be the case if this were necessary?


Now, I am having a problem with making a copy of a dynamic
array:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Var
Array1: Array of Char;
Array2: Array of Char;

Begin

...

Array2 := Copy(Array1, 1, 256);

End;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When I try to do this, I get an 'Incompatible types' error.
Why is this? The array types are exactly the same.
What is the proper way to copy dynamic arrays?

Maarten Wiltink

unread,
Apr 26, 2005, 2:14:18 AM4/26/05
to
"W. D." <NewsG...@US-Webmasters.com> wrote in message
news:426DCE...@US-Webmasters.com...
> Maarten Wiltink wrote:

>> [...] A3 is also freed when its containing object is, ...


> ^^^destroyed?
>
> Does 'destroyed' go here?

Yes. A style figure known as ellipsis, IIANM. Selective omission of
repetetive elements.


>> [...] you can set a dynamic array reference to nil for the same


>> effect as SetLength'ing it to zero elements. But that is an ugly
>> hack misguidedly prompted by implementation issues.
>
> What would be the case if this were necessary?

Dogs and cats would be living together, and fire would be raining
from the sky. It _isn't_ necessary. Use SetLength.


> Now, I am having a problem with making a copy of a dynamic
> array:

> Var


> Array1: Array of Char;
> Array2: Array of Char;

> Array2 := Copy(Array1, 1, 256);

> When I try to do this, I get an 'Incompatible types' error.


> Why is this? The array types are exactly the same.
> What is the proper way to copy dynamic arrays?

As was explained here once (quite a long time ago), the type
_constructors_ are exactly the same. The resulting types aren't.
Use a named type or declare both variables at the same time.

If that's not it, perhaps Copy is wrong and you need to use
something else or write your own.

Groetjes,
Maarten Wiltink


Jamie

unread,
Apr 27, 2005, 10:06:04 PM4/27/05
to
>
> So, my Array of Records will be automatically
> deallocated when the class that uses it is destroyed?

Let me try.

if you create a class, variables that are already
specified in the class with fixed heap sized fields (not dynamic),
get their space needed as soon as the constructor of the
class is call which in turn creates enough memory to allow
all heap type info for that class to exists.
the heap for these local variables work much the same way as
the local varibles work when calling functions! local storage is
created for you to allow occupation of these variables automaticly
from the stack which gets cleaned up when the function exits.
in classes, the memory that got allocated simply gets returned back
to the Run Time Lib to be re'used when the class free's it self.

now, dynamic variables are pointers just as the class code are
also pointers.
if you have local variables that are pointer types, only the pointers
them selfs will get created ( 4 bytes)( 32 bit Dword) how ever, any
items that these pointers look at is up to you at the construction time
to declare except for like RTL types (strings) and (Dynamic Arrays).
in anycase, with strings you simply treat them as you do any where.
with the RTL arrays how ever, you need to use the SetLength to
actually initiate them but no clean up should be needed because it is a
RTL type just like the string..
now here comes the tricky part. in any case!, when ever you create a
Class instant or pointer of any type with in a class constructor, you
need to free them in the destructor!
simply put, what memory you hog up, you release ..
Examples.

Var
MyArray:Array of Pointer;

that is a RTL type.
using the SetLength(MyArray, NumberofPointersWanted) is like using
SetLength(SomeString, ?);
space is created but managed like the strings are, you shouldn't
have to do anything in the constructor.

Now do something like this after you have initiated the MyArray.

GetMem(MyArray[0], NumberofBytes);

now this becomes a problem.
you need to free the memory that MyArray[0] is looking at before
exiting the Destructor.
ect////

0 new messages