Page 1 of 1

Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 5:43 pm
by AZJIO
I would like to set a negative number when returning a pointer from a procedure on errors. Can I do that? I found no mention of this in the reference file.

The point is that if we interpret the pointer as a number, the high bit may be considered as a negative value of the number.
If there is no error I should get the actual pointer to use in the following functions.

Code: Select all

Procedure FuncName()
    Protected *m

    If x
        ProcedureReturn -1
    EndIf
    If y
        ProcedureReturn -2
    EndIf
    If z
        ProcedureReturn -3
    EndIf

    ProcedureReturn *m
EndProcedure

*m = FuncName()
If *m < 0
	Debug "Error"
	Select *m
		Case -1
			Debug "Error=1"
		Case -2
			Debug "Error=2"
		Case -3
			Debug "Error=3"
		Default
; 			...
	EndSelect
EndIf

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 6:26 pm
by mk-soft
Maybe works, but I think it's programmed for unclean

Code: Select all


Prototype Invoke()

Procedure Func1()
  Debug "Function 1"
EndProcedure

Procedure Func2()
  Debug "Function 2"
EndProcedure

Procedure FuncName(Name.s, *Func.Integer)
  Protected *m
  
  If Not *Func
    ProcedureReturn -1
  EndIf
  If x
    ProcedureReturn -2
  EndIf
  If y
    ProcedureReturn -3
  EndIf
  If z
    ProcedureReturn -4
  EndIf
  ;
  Select Name
    Case "1"
      *Func\i = @Func1()
      
    Case "2"
      *Func\i = @Func2()
      
    Default
      ProcedureReturn -5
  EndSelect
  
  ProcedureReturn 0 ; Ok 
EndProcedure

Define function.Invoke

r1 = FuncName("2", @function)
If r1 
  Debug "Error=" + r1
Else
  function()	  
EndIf

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 6:50 pm
by NicTheQuick
Usually pointers are unsigned values. but depending on the programming language and available data types you can interpret them as negative values. Because of ASLR (Address Space Layout Randomization) you can in fact get negative values although you only use very less memory in your application.

But you can usually hide 2 bits in pointers if you assume that the pointers are always aligned. As you can see in this example the two lowest bits are always zero.

Code: Select all

Define s.s = "hi"
Define *p = AllocateMemory(4)
Procedure hi()
EndProcedure
DataSection
	hi:
	Data.i 0
EndDataSection

Debug Bin(@s)
Debug Bin(*p)
Debug Bin(@hi())
Debug Bin(?hi)
Okay, that's still a hack and maybe does not help you. So here's the best solution: Just use another parameter for additional return values of a function.

Code: Select all

Procedure FuncName(*ptr.Integer)
	Protected *m
	
	If Not *ptr
		ProcedureReturn 1
	EndIf
	If x
		ProcedureReturn 2
	EndIf
	If y
		ProcedureReturn 3
	EndIf
	If z
		ProcedureReturn 4
	EndIf
	
	*ptr\i = *m
	ProcedureReturn 0
EndProcedure

Define *m
error = FuncName(@*m)
If error
	Debug "Error"
	Select error
		Case 1
			Debug "Invalid argument"
		Case 2
			Debug "Error=2"
		Case 3
			Debug "Error=3"
		Case 4
			Debug "Error=4"
		Default
			; 			...
	EndSelect
EndIf

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 7:00 pm
by mk-soft
With macOS I have already seen odd functions addresses!

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 7:10 pm
by AZJIO
Then the old-fashioned analog of GetLastError()

Code: Select all

Global g_LastError

Procedure FuncName()
	Protected *m
	g_LastError = 0

	If x
		g_LastError = 1
        ProcedureReturn 0
    EndIf
    If y
		g_LastError = 2
        ProcedureReturn 0
    EndIf
    If z
		g_LastError = 3
        ProcedureReturn 0
    EndIf

    ProcedureReturn *m
EndProcedure

*m = FuncName()
If g_LastError
	Debug "Error"
	Select g_LastError
		Case 1
			Debug "Error=1"
		Case 2
			Debug "Error=2"
		Case 3
			Debug "Error=3"
	EndSelect
Else
	Debug *m
EndIf

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 7:20 pm
by NicTheQuick
AZJIO wrote: Sun Apr 20, 2025 7:10 pm Then the old-fashioned analog of GetLastError()

Code: Select all

Global g_LastError

Procedure FuncName()
	Protected *m
	g_LastError = 0

	If x
		g_LastError = 1
        ProcedureReturn 0
    EndIf
    If y
		g_LastError = 2
        ProcedureReturn 0
    EndIf
    If z
		g_LastError = 3
        ProcedureReturn 0
    EndIf

    ProcedureReturn *m
EndProcedure

*m = FuncName()
If g_LastError
	Debug "Error"
	Select g_LastError
		Case 1
			Debug "Error=1"
		Case 2
			Debug "Error=2"
		Case 3
			Debug "Error=3"
	EndSelect
Else
	Debug *m
EndIf
...and if you want to have it Threadsafe you can just use `Threaded` instead of `Global`, which is also automatically global and it will result in one version of `g_LastError` per Thread.

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 7:25 pm
by AZJIO
I realized that if a number does not support negative numbers, then it will not take this form, for example:

Code: Select all

a.a = -1
Debug a.a
So my question was bound to fail.

Re: Can a pointer be a negative number?

Posted: Sun Apr 20, 2025 11:28 pm
by Demivec
In PureBasic a pointer represents an unsigned address value but it is represented by a signed integer. This means the value can be negative.

You can select a special value or range of values to use as an error indicator. The value -1 can be used as a singular error indicator because its unsigned value is the highest possible memory location. You couldn't store more than a byte there so it wouldn't be the address of a structure, buffer, or procedure. Address zero is likewise a good error indicator.

Re: Can a pointer be a negative number?

Posted: Tue Apr 22, 2025 8:27 am
by Olli
(4-bits convention)
-> Signed value 0x0Fh will give -1
-> Unsigned value 0x0Fh will give 15

Pointer is an unsigned value : everything is positive, whatever the status of the most significant binary digit.

My suggest :

Code: Select all

Procedure exception1()
EndProcedure

Procedure exception2()
EndProcedure

Procedure exception3()
EndProcedure

Procedure exception4()
EndProcedure


 Procedure FuncName()
    Protected *m

    If x
        ProcedureReturn @exception1()
    EndIf
    If y
        ProcedureReturn @exception2()
    EndIf
    If z
        ProcedureReturn @exception3()
    EndIf

    ProcedureReturn *m
EndProcedure

*m = FuncName()
If *m < 0
	Debug "Error"
	Select *m
		Case @exception1()
			Debug "Error=1"
		Case @exception2()
			Debug "Error=2"
		Case @exception3()
			Debug "Error=3"
		Default
; 			...
	EndSelect
EndIf

Re: Can a pointer be a negative number?

Posted: Tue Apr 22, 2025 2:02 pm
by ricardo_sdl
For pointers I always return #Null when something went wrong or it wasn't possible to return a valid pointer. If I need to know what what happenened I add an output parameter like this:

Code: Select all

Procedure GetFunc(Name.s, *ReturnError.Long)
  
  If Name = "name1"
    ProcedureReturn *p1
  ElseIf Name = "name2"
    ProcedureReturn *p2
  EndIf
  
  If error1
    *ReturnError\l = -1
  Else
    *ReturnError\l = -2
  EndIf
  
  ProcedureReturn #Null
  
  
  
EndProcedure
And then I call like this:

Code: Select all

Define Name.s = "invalid"
Define ReturnError.Long
Define *Func = GetFunc(Name, @ReturnError)
If *Func = #Null
  Debug ReturnError\l
EndIf