Please explain what is Pointer()? lazarus / 21-General ---------------------------------------------------------------------- freemind001 · 2025-02-03 09:36 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  UI_SET_EVBIT = $40045564;  EV_KEY = $01;var  key: integer;  kbd: longint = -1; begin  kbd := fpOpen('/dev/uinput', O_WRONLY or O_SYNC);  ioRes += fpIOCtl(kbd, UI_SET_EVBIT, Pointer(EV_KEY));  for key := 0 to 248 do    iores += fpIOCtl(kbd, UI_SET_KEYBIT, Pointer(key));...end This code works as expected, but for the second call of fpIOCtl compiler says Warning: Conversion between ordinals and pointers is not portable The first call of fpIOCtl is ok for the compiler. What is the diffrence between Pointer() of const and of var? what is the point of casting integer to pointer and what does Pointer(key) actually mean? Why not @key? ---------------------------------------------------------------------- H₂SO₄ · 2025-02-03 10:12 Quote from: freemind001 on February 03, 2025, 10:36:54 amWhat is the diffrence between Pointer() of const and of var? There is no difference; in both instances it's a cast into a generic (untyped) pointer. Quote from: freemind001 on February 03, 2025, 10:36:54 amwhat is the point of casting integer to pointer and what does Pointer(key) actually mean? The declaration of  ioctl  requires that its third argument be a generic pointer. Pointer(key)  simply reinterprets the contents of  key  as a pointer to satisfy the type checker. Ultimately it is up to the specific device driver how exactly this value is used. Quote from: freemind001 on February 03, 2025, 10:36:54 amWhy not @key? That would take the address of  key,  which is a completely different operation that by itself has nothing to do with casting. ---------------------------------------------------------------------- freemind001 · 2025-02-03 10:43 Quote from: Khrys on February 03, 2025, 11:12:32 amThat would take the address of key,  which is a completely different operation that by itself has nothing to do with casting. from https://wiki.freepascal.org/Pointer A pointer is a variable that contains the memory address of a local or global variable, or the memory address of a value or complex object that has been created and stored in the heap part of a program's memory layout. Sorry, I don't get it. What's the diffrence? ---------------------------------------------------------------------- freemind001 · 2025-02-03 10:48 Quote from: Khrys on February 03, 2025, 11:12:32 amsimply reinterprets the contents of  key  as a pointer to satisfy the type checker. So, it is not the address of key? (I mean Pointer(key)) What is it then?)) ---------------------------------------------------------------------- Thaddy · 2025-02-03 10:54 No, in this case it is a pointer CAST: it mimics the value of key as if it were a pointer. The real address of key as a raw pointer is @Key or addr(key), but here you don't need that, even more you don't want that because it would make the code wrong. That is basically the same as Khrys wrote in other words. ---------------------------------------------------------------------- 440bx · 2025-02-03 11:32 Maybe an example will make it easier to understand, consider the following code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  i : integer = $1234;  p : pointer; begin  { attempting to set the value of "p" to be equal to the value of "i" fails because "i" is  }  { not a pointer, therefore the compiler rejects that statement.                          }   p := i;  { attempt to set "p" to the value $1234 (the value of "i") fails                  }   p := pointer(i); { tells the compiler to treat "i" as if it had been declared to be a      }                 { pointer instead of an integer (for that single statement)               }   { now the pointer "p" has the value $1234 (the value of "i")                               }   { the "pointer(i);" tells the compiler to forget that "i" is an integer and consider it a  }   { pointer instead.  Note that this does NOT change the value of "i", it just changes the   }  { way it is interpreted (in this case, from integer to pointer.)                           }   { pointer(key) simply tells the compiler to forget whatever type "key" was declared to be  }  { and instead, for that single statement only, act as if it had been declared to be a      }  { pointer.                                                                               }end. Line 9, the assignment "p := i;" will be rejected by the compiler because "i" is an integer and an integer cannot be assigned to a pointer ("p" in this case.) Line 11, the "pointer(i);" part of the statement tells the compiler that "i" is to be considered a pointer (for that single statement) and, since now "i" is (temporarily) a pointer instead of an integer, it can be assigned to "p". That temporary re-typing of a variable is called a cast.  It does not change the values stored in the variable, it only changes how they are interpreted (their type, in this case from type integer to type pointer) HTH. ---------------------------------------------------------------------- freemind001 · 2025-02-03 11:46 OK, I take it this is a formal operation, in order to satisfy the definition of the function, am I right? After casting the value is still 0..248, but of type pointer? How do I get rid of the warning project1.lpr(25,42) Warning: Conversion between ordinals and pointers is not portable ---------------------------------------------------------------------- 440bx · 2025-02-03 11:58 Quote from: freemind001 on February 03, 2025, 12:46:49 pmOK, I take it this is a formal operation, in order to satisfy the definition of the function, am I right? Correct. Quote from: freemind001 on February 03, 2025, 12:46:49 pmAfter casting the value is still 0..248, but of type pointer? Correct. Quote from: freemind001 on February 03, 2025, 12:46:49 pmHow do I get rid of the warning project1.lpr(25,42) Warning: Conversion between ordinals and pointers is not portable TTBOMK, the compiler will emit the warning whenever appropriate (which is likely always),  That said, if you are using Lazarus, you can right click on the line and select one of the "hide" options from the popup menu but, this only works when compiling from Lazarus (which is what most people do.) HTH. ---------------------------------------------------------------------- freemind001 · 2025-02-03 12:09 Thank you ---------------------------------------------------------------------- 440bx · 2025-02-03 12:26 Quote from: freemind001 on February 03, 2025, 01:09:01 pmThank you You're welcome. ---------------------------------------------------------------------- Thaddy · 2025-02-03 12:55 You can also compile with the extra option -vq which will show you the warning number and you can subsequently turn that off by {$WARN OFF} That is what people do that do not use the Lazarus IDE. I usually specify -vewhnlq to catch al notes, hits, warnings and errors with line numbers and error numbers ---------------------------------------------------------------------- freemind001 · 2025-02-03 14:10 Will there be any problems with this code when compiling on other linux-based operating systems? if so, which ones? I'm using Ubuntu 24.04 x64 ---------------------------------------------------------------------- Thaddy · 2025-02-03 14:38 No, should not cause any problems. ---------------------------------------------------------------------- Warfley · 2025-02-03 19:40 The warning is, as it states, conversion to and from pointers is not necessarily portable. So for example in ARM architectures, pointers need to be aligned, so $xyz0 is a valid pointer while $xyz1 is not. This is why fpc throws a warning when you cast between those types. The problem here is a different one, IOCTL can be implemented by many drivers, using different kinds of data (as long as its the size of a pointer), some need pointers, others need integers. This is why the C binding of IOCTL is: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i int ioctl(int fd, unsigned long op, ...);Note that it uses varargs to enable this format agnostic implementation. The FPC binding on the other hand is: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function FpIOCtl(Handle: cint; Ndx: TIOCtlRequest; Data: Pointer): cint;Which always takes a pointer, under the assumption that you can just cast your type to pointer. The Problem here is not the warning, but rather the FPC binding not covering other types, like the C binding does The reason why the waning is only with a variable, I would assume is because with constants the compiler can check if it is a valid pointer for the target platform, while with a variable, it does not know at compiletime if it is valid or not. But thats just a theory ---------------------------------------------------------------------- PascalDragon · 2025-02-04 21:02 Quote from: Warfley on February 03, 2025, 08:40:23 pmThe reason why the waning is only with a variable, I would assume is because with constants the compiler can check if it is a valid pointer for the target platform, while with a variable, it does not know at compiletime if it is valid or not. But thats just a theory It has simply to do with the introduction of 64-bit support as users needed to be warned if they cast Integer or LongInt to Pointer or the other way round (which was very common from Delphi). This warning can't really be solved using code, because types like NativeInt are declared as aliases to LongInt or Int64 (or the corresponding 8- or 16-bit types) depending on the platform instead of being compiler internal types which would allow the compiler to drop the warning if NativeInt or NativeUInt is involved. ---------------------------------------------------------------------- H₂SO₄ · 2025-02-05 06:41 Out of curiosity, does anyone here know any architectures where  void* -> size_t -> void*  round-trips genuinely cannot work? The only example I can think of is 16-bit x86 with far pointers. ---------------------------------------------------------------------- Thaddy · 2025-02-05 10:28 void* is in pascal a procedure. It should not have a return value, so can not be chained. In C it also indicates that there is no valid return value. We used to use some trickery in the past that we knew gave us a reliable return value but that is neither documented nor good practice. Apart from the short first sentence this only refers to C. void means empty, it is not a result. That is on all C platforms. Has nothing to do with 16/32/64/128/whatever. You can not chain void* and if you do... because there is a value in a register... you are doing things very wrong. So @Khrys, what makes you think otherwise? That is bad C programming. But this is a Pascal forum. ---------------------------------------------------------------------- 440bx · 2025-02-05 12:11 @Thaddy, I don't think @Khrys is talking about procedures or functions. I believe he is talking about the amount of storage occupied by a pointer normally being the same as the integer type native size (NativeInt, size_t, ptrint, etc, depending on language and compiler.) One well known exception is the one he mentioned, 16:16 far pointers. ---------------------------------------------------------------------- H₂SO₄ · 2025-02-06 07:00 Quote from: 440bx on February 05, 2025, 01:11:52 pm@Thaddy, I don't think @Khrys is talking about procedures or functions. I believe he is talking about the amount of storage occupied by a pointer normally being the same as the integer type native size (NativeInt, size_t, ptrint, etc, depending on language and compiler.) One well known exception is the one he mentioned, 16:16 far pointers. You got it! I was probably too vague in my question. I was asking about platforms where generic pointers cannot be converted to native-sized integers and then back to pointers because  SizeOf(Pointer) > SizeOf(PtrInt),  meaning that information gets lost in the conversion. In other words, I wanted to know on which platforms the warning "Conversion between ordinals and pointers is not portable" should turn into a hard error. For example, on 16-bit x86 attempting to fit a far pointer into a native-sized integer would essentially be equivalent to this nonsense (I think): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TFarPointer = record    Segment, Offset: Word;  end; var  PointerToItself: Word; // Native 16-bit word size; could also be PtrUInt (would still fail) begin  PointerToItself:= TFarPointer(@PointerToItself); // Cannot convert structured type to ordinalend. ---------------------------------------------------------------------- Warfley · 2025-02-06 09:52 Quote from: Khrys on February 05, 2025, 07:41:21 amOut of curiosity, does anyone here know any architectures where  void* -> size_t -> void*  round-trips genuinely cannot work? The only example I can think of is 16-bit x86 with far pointers. Looking at the C standard section 7.22.1.4, it explicitly allows to cast pointers into type intptr_t/uintptr_t  and back, as long as the value is not changed in between. It should be noted that this guarantee is solely given for these types, not for size_t or other int types, and also that the conversion to pointer is not guaranteed to work if you modify the pointer in between. All of that is undefined behavior. So you are allowed to use (u)intptr_t to store pointer values, but you are not allowed to modify them or to use another int type to do so. At least according to the standard. If you need to do this, you must check the compiler manual for the target architecture if this is allowed. But your explicit question, if you replace size_t with intptr_t, then the answer is: This is always allowed. ---------------------------------------------------------------------- PascalDragon · 2025-02-06 22:03 Quote from: Khrys on February 05, 2025, 07:41:21 amOut of curiosity, does anyone here know any architectures where  void* -> size_t -> void*  round-trips genuinely cannot work? The only example I can think of is 16-bit x86 with far pointers. Just like you should use (u)intptr_t in C to solve this (as Warfley mentioned) in FPC you should use Ptr(U)Int and CodePtr(U)Int. It has always the same size as the corresponding Pointer or CodePointer type. Quote from: Thaddy on February 05, 2025, 11:28:56 amvoid* is in pascal a procedure. C's void* in Pascal is just a Pointer. A procedure pointer in C would be void*() (note the parenthesis).