Recent

Author Topic: Passing a variable by address  (Read 4791 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Passing a variable by address
« on: April 30, 2021, 05:13:43 pm »
My understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var.

My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const.

What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal?

C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied?

Code: Pascal  [Select][+][-]
  1. (* Wait until we can be reasonably confident that we're not still in the middle
  2.   of an input line.
  3. *)
  4. procedure WaitInputGap(handle: TSerialHandle; var termFlag: boolean);
  5.  
  6. var
  7.   avail: integer;
  8.  
  9. begin
  10.   SerFlushInput(handle);
  11.   repeat
  12.     if fpIoctl(handle, FIONREAD, @avail) <> 0 then
  13.       break;
  14.     Sleep(50);
  15.     SerFlushInput(handle)
  16.   until (avail = 0) or termFlag
  17. end { WaitInputGap } ;
  18.  

As a subsidiary question and noting that I think this was discussed a few weeks ago, is it possible for a program's main unit to expose the termination flag as a variable or (better) a function or (best) a read-only unit property?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

egsuh

  • Hero Member
  • *****
  • Posts: 1760
Re: Passing a variable by address
« Reply #1 on: April 30, 2021, 05:37:40 pm »
I'm not sure I understand you correctly. But can't pointers do what you want?

In the following example, if anything asynchronously change the content of PInt^, then it will be reflected within the procedure DoSomething.  Haven't checked syntax nor tested. Even not sure "pointer to interger" is correct syntax. But I know that there are similar declarations.
Code: Pascal  [Select][+][-]
  1. var
  2.      PInt: pointer to integer;
  3.  
  4. procedure DoSomething (apint: pointer to integer);
  5. begin
  6.     ...
  7.     if apint^ = 0 then ...
  8.  
  9. end;
  10.  
  11. begin
  12.      ....
  13.      New(PInt);
  14.      DoSomething (PInt);
  15.      ....
  16. end;

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #2 on: April 30, 2021, 05:49:03 pm »
I'm not sure I understand you correctly. But can't pointers do what you want?

Yes, but a pointer is synonymous with a var (in fact somewhat less safe, since unless protected by const it can itself be changed) so good practice would suggest that something stronger be used where the function is not expected/allowed to change the parameter.

Perhaps a constref? Would this guarantee appropriate behaviour and are there any gotchas?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

egsuh

  • Hero Member
  • *****
  • Posts: 1760
Re: Passing a variable by address
« Reply #3 on: April 30, 2021, 06:04:18 pm »
I don't think const would do. Value will be passed with const parameter.
We may think of a read-only property. The field itself is not accessible from the procedure, but it can be changed directly by other part of program. For example a variable is defined in unit A, property is defined in unit B which uses A, and your procedure is defined within unit C, which uses B but not A.

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Passing a variable by address
« Reply #4 on: April 30, 2021, 06:39:56 pm »
Perhaps a constref? Would this guarantee appropriate behaviour and are there any gotchas?

constref does indeed almost what you want: it guarantees that the parameter will be passed by reference. Only gotcha  I can think of is that it's not exactly like volatile so depending on target, optimization level, etc. it might not behave consistently: e.g. the value might be kept in a register after some operation and be used from there instead of re-reading it, etc.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #5 on: April 30, 2021, 07:22:41 pm »
constref does indeed almost what you want: it guarantees that the parameter will be passed by reference. Only gotcha  I can think of is that it's not exactly like volatile so depending on target, optimization level, etc. it might not behave consistently: e.g. the value might be kept in a register after some operation and be used from there instead of re-reading it, etc.

Thanks very much. I'll make the tentative assumption that since there's typically an OS call or some string manipulation in the loop the underlying pointer will get dereferenced regularly. This might actually be a good place for a macro: expand as constref or var as required.

Under the circumstances I think I'd prefer having the termination flag be some sort of main-unit global, but the important thing is to have something that works.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1412
Re: Passing a variable by address
« Reply #6 on: April 30, 2021, 08:11:14 pm »
My understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var.

My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const.

What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal?

C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied?
*snip*

AFAIK 'volatile' modifier in C/C++ doesn't relate to parameter passing but to hint the compiler that the variable ca be suddenly changed by some external signal, interrupt handler or thread. In such a case the compiler shouldn't optimize it by putting in register or so.

Besides, in FPC there has 'interrupt' modifier for routines and also 'bare' ports - AVR.
IMHO that (volatile variables) are becoming an important subject for embedded targets. It would probably be good if someone could shed some light on the issue. Anyone?

Regards,

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

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #7 on: April 30, 2021, 09:42:39 pm »
AFAIK 'volatile' modifier in C/C++ doesn't relate to parameter passing but to hint the compiler that the variable ca be suddenly changed by some external signal, interrupt handler or thread. In such a case the compiler shouldn't optimize it by putting in register or so.

An explicit "shouldn't optimise by"... yes, good point.

I've ended up putting this near the top of the unit and using where appropriate:

Code: Pascal  [Select][+][-]
  1. {$macro on}
  2. {$define ROREF:= constref }             (* Use constref or if necessary var     *)
  3. [code]
  4.  
  5. By and large I'm strict on checking correct operation of anything questionable, but I suspect that correct operation of this one wouldn't be a particularly easy thing to verify... I suppose that a program could send a SIGINT to itself and check that a flag had changed as soon as the syscall returned. I probably won't bother in this particular case, since the parameter is /only/ being used to ensure that the program terminates rapidly and in good order, and it's not going anywhere near a customer.
  6.  
  7. TBH I think FPC should have volatile and static modifiers... and I don't give a damn whether they're too "C-like" for some people >:-|
  8.  
  9. MarkMLl
  10.  
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

ccrause

  • Hero Member
  • *****
  • Posts: 1094
Re: Passing a variable by address
« Reply #8 on: April 30, 2021, 10:13:18 pm »
There is a volatile intrinsic in trunk.  Marking a particular access as volatile should force the compiler to load/store as appropriate.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #9 on: April 30, 2021, 10:45:33 pm »
There is a volatile intrinsic in trunk.  Marking a particular access as volatile should force the compiler to load/store as appropriate.

Thanks very much, noted. So presumably that could be used with constref to both prevent attempted modification by a function and ensure that the function was attentive to external modification.

Since it's an intrinsic I presume that the only way of checking for its existence is by having conditional compilation look carefully at the compiler version number.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1412
Re: Passing a variable by address
« Reply #10 on: May 01, 2021, 11:59:13 am »
Digging further in that 'volatile' thing I rather found it extremely vague and mistreated by the compilers. The only reasonable rationale behind it would be for I/O mapping and the side effects on the peripherals, something like: *ttyport = a[i++];

cited: https://lwn.net/Articles/233482/ and also
https://stackoverflow.com/questions/38235112/why-is-a-volatile-local-variable-optimised-differently-from-a-volatile-argument
https://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf

Thus, I agreed, the volatile intrinsic is much more appropriate than the storage attribute, moreover, it won't introduce ambiguity between volatiles, refs to volatiles, pointers to volatiles, etc.

@MarkMLl
IMHO, doing simple variable checks for graceful termination should be perfectly OK and without any concern, since it will probably reside in separate subroutine and won't be 'swallowed' through CSE or whatever optimization cleverness...
At least, as long as the following continues to work, everything should be fine :)
Code: Pascal  [Select][+][-]
  1. procedure TMyThread.Execute;
  2. begin
  3.   while not Terminated do ...
  4. end;
  5.  
« Last Edit: May 01, 2021, 12:03:27 pm by y.ivanov »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

jamie

  • Hero Member
  • *****
  • Posts: 7602
Re: Passing a variable by address
« Reply #11 on: May 01, 2021, 12:27:02 pm »
My understanding is that if a procedure or function parameter is to both convey information on entry and potentially be modified on exit, then it must be declared as var.

My understanding is also that if a procedure or function parameter is to convey information on entry but will not be modified, then it should be declared as const.

What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal?

C/C++ would call it volatile, and the statements above would imply that it should be const, but would this guarantee that even a simple variable would be passed by address rather than being copied?

Code: Pascal  [Select][+][-]
  1. (* Wait until we can be reasonably confident that we're not still in the middle
  2.   of an input line.
  3. *)
  4. procedure WaitInputGap(handle: TSerialHandle; var termFlag: boolean);
  5.  
  6. var
  7.   avail: integer;
  8.  
  9. begin
  10.   SerFlushInput(handle);
  11.   repeat
  12.     if fpIoctl(handle, FIONREAD, @avail) <> 0 then
  13.       break;
  14.     Sleep(50);
  15.     SerFlushInput(handle)
  16.   until (avail = 0) or termFlag
  17. end { WaitInputGap } ;
  18.  

As a subsidiary question and noting that I think this was discussed a few weeks ago, is it possible for a program's main unit to expose the termination flag as a variable or (better) a function or (best) a read-only unit property?

MarkMLl
if I understand your post...

 You are concerned about a variable changing while you are handling the last value of it within a function from the parameter entry ?

 if that is the case, you don't want to use CONST, CONSTREF, Var or OUT because CONST will free for the compiler to optimize the code so it could be what ever the compiler see's fit when it constructed the function.
 
 CONSTREF ensures that it's always a pointer (VAR) referenced but you still can only read from it.

 and of course VAR and OUT is a pointer reference.

 If you want a value that remains constant within the function then just pass it directly with NO CONST, VAR or OUT.. All simply types will be Register or stacked pushed and there for remain constant within your function and you are free to change it of course

 If you are in a case where you need a locked value and also need to write back then you need to pass it as two parameters, one as I have said to prevent change and the other as a VAR so  you can write back

in C/C++ the Volatile is only a compiler optimizer to instruct the compiler that the value may change so it needs to may a choice about how it references it, from a Register loaded once or always referenced from the original source. This depends on the code, for example a control loop that must not have its value changed during the intrinsic of the loop etc..
The only true wisdom is knowing you know nothing

alpine

  • Hero Member
  • *****
  • Posts: 1412
Re: Passing a variable by address
« Reply #12 on: May 01, 2021, 12:46:17 pm »
Wouldn't it be better then:
Code: Pascal  [Select][+][-]
  1. type
  2.   TTerminationFunc = function: Boolean;
  3.  
  4. function IsTerminated: Boolean;
  5. begin
  6.    Result := your_termination_flag;
  7. end;
  8.  
  9. procedure WaitInputGap(handle: TSerialHandle; IsTerm: TTerminationFunc);
  10. begin
  11.   ...
  12.   until (avail = 0) or IsTerm
  13. end;
  14.  
  15.   ...
  16.   WaitInputGap(AHandle, @IsTerminated);
  17.   ...
  18.  
  19.  
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #13 on: May 01, 2021, 12:49:19 pm »
@Jamie, you have got TOTALLY the wrong end of the stick.

Quote
What is the correct declaration of a parameter which will not be changed by anything the function does, but may be changed asynchronously by a unix-style signal?

...plus obviously look at the example WHICH YOU QUOTED. The whole point is that a termination signal signal detected in a unix-style console program SHOULD be picked up promptly and break any loops.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 8551
Re: Passing a variable by address
« Reply #14 on: May 01, 2021, 12:53:41 pm »
Wouldn't it be better then:
Code: Pascal  [Select][+][-]
  1. type
  2.   TTerminationFunc = function: Boolean;
  3.  
  4. function IsTerminated: Boolean;
  5. begin
  6.    Result := your_termination_flag;
  7. end;
  8.  
  9. procedure WaitInputGap(handle: TSerialHandle; IsTerm: TTerminationFunc);
  10. begin
  11.   ...
  12.   until (avail = 0) or IsTerm
  13. end;
  14.  
  15.   ...
  16.   WaitInputGap(AHandle, @IsTerminated);
  17.   ...
  18.  
  19.  

Perhaps, but it's just layering complexity where it's not really needed. The best- IMO- solution would be a read-only export of the termination flag from the main unit. Or possibly moving it to the utility unit in which most of its usage occurs, but I find that unnatural since a signal handler so clearly pertains to the main program.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018