Jump to content
Sign in to follow this  
Sonjli

Pointers... loops...

Recommended Posts

Hi guys,

I hope this is the right topic to place my doubts.

I use a DLL written in C and it need some work with pointers.

I admit I am not very prepared with pointers (scholastic remembrances), so I hope my question to be clear.

 

I have this structure:

 

   PODBALMMSG2 = ^ODBALMMSG2;

   ODBALMMSG2 = packed record
      alm_no: LongInt;
      atype: SmallInt;
      axis: SmallInt;
      dummy: SmallInt;
      msg_len: SmallInt;
      alm_msg: array [0 .. 63] of AnsiChar;
   end;

And this is the function I use to populate this structure and read it:

procedure TRdAlmMsgActionA.InternalRdAlmMsg;
var
   iAlarm: Integer;
   LErrorCounter: Integer;
   rn: SmallInt;
   popmsg: PODBALMMSG2;
begin
   FPath := '';
   LErrorCounter := 0;
   // A random number the DLL need to have any initial value
   rn := 50;
   try
      // A pre-filled number with "max paths" (FConnection.MachinePaths) to read from DLL 
      for var J := 1 to FConnection.MachinePaths do
      begin
         // A DLL function to loop between "Paths" until "FConnection.MachinePaths"
         FConnection.ErrHandle := cnc_setpath(FConnection.ConnHandle, J);
         if FConnection.ErrHandle <> EW_OK then
         begin
            Inc(LErrorCounter);
            Continue;
         end;

         // Here I need help: is this algorithm ok?
         new(popmsg);
         try
            // The DLL fill "popmsg" with an array of "PODBALMMSG2" with length "rn"
            FConnection.ErrHandle := cnc_rdalmmsg2(FConnection.ConnHandle, -1, rn, popmsg);

            if FConnection.ErrHandle <> EW_OK then
            begin
               Inc(LErrorCounter);
               Continue;
            end;
            // Loop for "popmsg" of length "rn"
            for var I := 0 to rn - 1 do
            begin
               // Here I do reading stuff with "popmsg^.alm_no", "popmsg^.aType", etc.
               
               // Incremet pointer to read next array value
               Inc(popmsg);
            end;
         finally
            // Bring the pointer at the start of the array
            Dec(popmsg, rn);
            // Free the pointer
            Dispose(popmsg);
         end;
      end;
   finally
      cnc_setpath(FConnection.ConnHandle, 0);
   end;
end;

 

I have so many doubts about this:

- Have the popmsg pointer to be brought at the start before dispose?

- Is the loop right?

- Is the "new()" function right to allocate the pointer?

- And so on...

 

Any help?

 

Thanks in advance.

Eddy

 

 

 

 

 

 

Share this post


Link to post

First you need to know the maximum length of "rn" and allocate that maximum from start. Something like this:

popmsg: array[0..100] of ODBALMMSG2;

and call it like this:

FConnection.ErrHandle := cnc_rdalmmsg2(FConnection.ConnHandle, -1, rn, @popmsg[0]);

This way you don't need pointers.

Share this post


Link to post

Hi Cristian,

thanks for your answer.

 

How do I allocate popmsg?

How do I dispose the array?

 

How do I read an element? @popmsg[4].alm_no or popmsg[4]^.alm_no?

 

Eddy

Edited by Sonjli

Share this post


Link to post
1 hour ago, Sonjli said:

How do I [...]

The array is static and is allocated on the stack. You could also use a dynamic array to have it allocated on the heap. Static is faster but stack space is limited.

Regardless the array is automatically deallocated when it goes out of scope.

 

Anyway:

 

procedure TRdAlmMsgActionA.InternalRdAlmMsg;
const
  MaxMsgs = 50;
var
  rn: SmallInt;
  popmsgs: array[0..MaxMsgs-1] of ODBALMMSG2;
  i: integer;
begin
  ...
  while (True) fo
  begin
    rn := MaxMsgs;

    // rn on entry contains max items the buffer can hold
    // rn on exit contains number of items now in buffer
    // See: https://www.inventcom.net/fanuc-focas-library/misc/cnc_rdalmmsg2 
    FConnection.ErrHandle := cnc_rdalmmsg2(FConnection.ConnHandle, -1, rn, @popmsgs[0]);

    if (rn = 0) then
      break; // No more available

    for i := 0 to rn-1 do
    begin
      popmsgs[i].whatever...
    end;
  end;
end;

 

Share this post


Link to post

Thank you Anders, really precious.

 

As you see I use the FOCAS library to connect some CNC and sometimes there are some traps...

 

Are you skilled with FOCAS? May I ask you any questions sometimes if I am in danger? 😅

Share this post


Link to post
4 minutes ago, Sonjli said:

Are you skilled with FOCAS?

Never used it.

I just Googled "cnc_rdalmmsg2" to find out if the function provided some means of determining the required buffer size. Like it is common with WinAPI functions (ERROR_INSUFFICIENT_BUFFER).

Share this post


Link to post

The API is documented and I used it for years. The my only problem is about pointers... I know, don't say a word 😉

 

Do you have any Pascal related documentation\manual about pointers?

 

Thanks everybody.

 

Eddy

Share this post


Link to post

You need first to understand what a pointer is and how things like pointers and other types are stored into memory. Maybe diving a little in assembler will help you to understand what is under the hood.

I can't imagine a good programmer that don't know a little how CPU works or how things are stored into memory.

Share this post


Link to post
11 minutes ago, Cristian Peța said:

Maybe diving a little in assembler will help you to understand what is under the hood.

This has to be, in my opinion, one of the worst pieces of advice I have ever come across. 

Share this post


Link to post
41 minutes ago, Sonjli said:

 

Do you have any Pascal related documentation\manual about pointers?

Type delphi pointers into a search engine and start there. I'm sure there will be a mix of hits. Some better than others. Read the top 10, form a view on which are good and which are not. Reread the good ones. 

  • Thanks 1

Share this post


Link to post
12 minutes ago, David Heffernan said:

This has to be, in my opinion, one of the worst pieces of advice I have ever come across. 

I started with Basic. The next was Z80 assembler. But assembler opened my eyes and is a base of understanding how things works.

 

P.S. I can't imagine that someone can do a good thing in Spring4D for example without understanding CPU and memory. Also if someone does not have this knowledge working with C or C++ is a waste of time in my opinion. Then better Java.

Edited by Cristian Peța

Share this post


Link to post

Edit: I rewrote this on my blog: https://larsfosdal.blog/2019/10/31/demystifying-pointers-in-delphi/   

 

Having a general understanding of how memory and addressing works, helps a bit for pointers.  Learning assembler gives you that knowledge, but there are simpler ways to think about it.


A pointer is a memory location that contains the address to the actual data you want

Think of a street with houses. Make a list of the houses and their addresses. 
This is a list of pointers. Each pointer leads to the actual house it refers to.


As you move through the list and follow each pointer, you can visit each house.

Street of houses (i.e. your blocks of data, 1Kb each)
10k          11k          12k          13k         14K
+------------+------------+------------+------------+------------+
|Apple       |Pear        |            |Banana      |Orange      |
|    H1      |     H2     |            |    H3      |     H4     |
|            |            |            |            |            |
+------------+------------+------------+------------+------------+

Your list of addresses (aka 4 byte pointers) is stored at memory address 100k
var 
  ptrlist: array[0..3] of pointer;

assuming the list has been initialized with the correct addresses  
ptrlist[0] 100k		contains 10k
ptrlist[1] 100k+4	contains 11k
ptrlist[2] 100k+8	contains 13k
ptrlist[3] 100k+12	contains 14k

for var ix := 0 to Length(ptrlist) - 1
do begin
  here, ptrlist[ix] = 10k,11k,13k,14k, and ptrlist[ix]^ = whatever value that is stored in the respective house the pointer addresses
  f.x.
  ptrlist[1] contains 11k (and that value is stored at 100k+4, and ptrlist[1]^ points to 'Pear', i.e. whatever is stored from address 11k


Why the empty house?
To exemplify that your list of pointers may be a consecutive array or linked list, but the data each pointer points to does not necessarily need to be consecutive.
 

Now, if you address ptrlist[4] - you are out of bounds on the pointer list, and if you are so "lucky" that the address @ptrlist[4] (which is 100k+16) is not inaccesible, then ptrlist[4]^ will point you to whatever random value that pointer contains,, and most likely give you an access violation, or for sure - point you to data you are not meant to visit.

  • Like 3
  • Thanks 1

Share this post


Link to post
   PODBALMMSG2 = ^ODBALMMSG2;

   ODBALMMSG2 = packed record
      alm_no: LongInt;
      atype: SmallInt;
      axis: SmallInt;
      dummy: SmallInt;
      msg_len: SmallInt;
      alm_msg: array [0 .. 63] of AnsiChar;
   end;

 

 

In Delphi,if you has code like this:

 

procedure DoSometiing(xxxxx: xx);

var

  MyR: ODBALMMSG2

begin

   ////do something...

end;

 

Here, you got a record MyR, its memory is prepared statically. It is a instance, you can use it directly.  And the pointer of this instance is: @MyR.

 

If you has code like this:

procedure DoSometing(xxx: xxx);

var

  MyR_P: PODBALMMSG2

begin

   /// Here, MyR_P is a pointer that type is PODBALMMSG2 but it is a pointer, you can just use a normal pointer type instead PODBALMMSG2.

  /// Here, MyR_P is just a variable, there is no instance, no memory that store data. If you want use it, you must allocate memory for it. And, you must free the memory when you want to give up it.

   MyR_P := GetMem(SizeOf(ODBALMMSG2));

  try

     do something...

  finally

    FreeMem(MyR_P);

  end;

 

 

   /// or, you can use this function:

   New(MyR_P);

  try

    Do something....

 finally

  Dispose(MyR_P);

end;

end;

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×