About use of pointers

Just starting out? Need help? Post your questions and find answers here.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

About use of pointers

Post by Psychophanta »

What is rather:

a=@"qwer"

or

*a=@"qwer"

And...

*hWnd=OpenWindow(0,300,300,500,300,0,"")

or

hWnd=OpenWindow(0,300,300,500,300,0,"")
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Maybe this post explains it a bit?

viewtopic.php?p=24846#24846

If not, ask...

Timo
quidquid Latine dictum sit altum videtur
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Sorry Timo, it is not the matter.
I understand the use and meaning of * and @ prefixes in PB.

But the matter is that i've notice that some PB programmers use long type variables as pointers, and PB works fine with it, and this fact dislike to me.

For example, i have seen: something like a=@"name", or a=@pop$. PB must show an error before these kind of things.

Another example and curious. The other day, i noticed a strange thing:
in a program i wrote:

Code: Select all

hWnd=OpenWindow(0,300,300,500,300,#PB_Window_SystemMenu|#PB_Window_TitleBar,"BINGO")
If hWnd=0
  MessageRequester("Error","Something fails",0)
  End
EndIf

If OpenWindowedScreen(hWnd,300,300,500,300,1,0,0)=0
  MessageRequester("Error","Something fails",0)
  End
EndIf
and sometimes (and only sometimes :o ) PB debugger gives an error saying: " 'WindowID' isn't a valid window descriptor ".
Logically, PB must show this error always, but not only sometimes when is executed.

If you write an asterisk (which would be more coherent) before hWnd, this error is never shown, and program works normally.

Thanx!
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Actually, this is a thing, that i very much like on the PB language.

You don't have to care about, what it is you store somewhere, as long
as it fits where you put it. This means, you can put everything in a LONG
variable, no matter, if it is a handle, a pointer to a string, or just a number
you need to count something in your program.

Have a look at C for example. You have hell of a lot of different types
there, each for a different purpose, but most of them are just 32bit
variables, nothing else. And I really hate all those type conversions you
have to do there.

That's the good thing about PB. All that is 32bit variable, is just a long.
You can still use a pointer to store your Window handle, if you like, but
if not, you can just copy it to a LONG, and live happily ever after :D

To come back to your original question:
What is a pointer anyway?

Look at what the ASM output of PB shows us:
*Pointer is represented by "p_Pointer", and Variable.l is replaces by
"v_Variable", both are of dword type. So where's the difference?
Actually, ASM doesn't care about what's inside, just like PB does.

It is just the compiler, who complains on other languages. If the language
has strict rules in that matter, like C has, then the compiler will stop and
say: hey, this isn't a HANDLE, it's a HWND, make a conversion! (well,
he'd say something similar at least :wink: )

I'm really glad the PB compiler doesn't do this.
I personally prefer using the Pointer symbol '*' only in places, where it
makes sense to me. Which is, at places, where you actually have a Pointer,
and also try to read, what is stored at where it points to. (which is what you never do with a Window handle for example). For example, you have
a pointer to a Structure of data. This is where it makes sense to me.

But this is up to the individual programmer. And this is my whole point:
If you like to use *hWnd, because it reminds you of, that this is a handle
or something, that's fine, that's the strong point of PB :!:

Well, so much about that...

Timo
quidquid Latine dictum sit altum videtur
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

freak wrote:variables, nothing else. And I really hate all those type conversions you have to do there.
Pointer errors (passing the wrong thing) would be so much easier to find if PB had even the simplest type checking but, like C, you could still override it.
has strict rules in that matter, like C has, then the compiler will stop and say: hey, this isn't a HANDLE, it's a HWND, make a conversion! (well,
he'd say something similar at least :wink: )
Not very strict as you can just tell the compiler that it really is a different type. And it trusts you ;)
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Hi, Timo.

Of course, you are right.
In fact a 32 bit pointer is a 32 bit number, there are not difference.
And it is good that PB compile don't find differences on it as do x86 processors.
I find this as an advantage of PB too.

The only disadvantage is when i watch PB code; i get a bit mess.
Perhaps it would be good that PB show a warning when assign a pointer to a long, but thinking again perhaps it would be an unnecessary complication.


About the "'WindowID' isn't a valid window descriptor" debugger message i explained you; this is the complete code:

Code: Select all

Procedure bingo()
  BackColor(250,250,250)
  FrontColor(0,0,0)
  Box(0,0,500,300)
  Locate (0,20)
  DrawText("Push LMB for balls.")
  DefType.b
  Dim B(90)
  For J=1 To 90:B(J)=J:Next
  For J=90 To 1 Step -1:XX=Random(J-1)+1:C=B(XX)
    Repeat
      EventID.l=WindowEvent()
      If EventID=#PB_EventRepaint   ; If the user has resized the window or anything, we will repaint our graphic
      ElseIf EventID=#PB_EventCloseWindow:Goto SAL
      EndIf

      ;press-key positive edge detection:
      ExamineKeyboard()
      pk=KeyboardPushed(#PB_Key_All)
      If pka<>pk:pka=pk;then edge detected
        If pk<>0;then it was positive edge
          pki=1
        EndIf
      Else;then not edge detected
        pki=0
      EndIf
    Until EventID=#WM_LBUTTONDOWN Or pki=1
    While XX<J:B(XX)=B(XX+1):XX+1:Wend
    B(J)=C
    po.w= 60 + 20 * Val(Left(StrU((90-J)/16,#Word),FindString(StrU((90-J)/16,#Word),".",1)+1))
    pu.w= ((90 - J) & 15) * 30
    Locate (pu.w,po.w)
    DrawText(Str(B(J)))
  Next
  If MessageRequester("Bingo program","Another?"+Chr(10),#PB_MessageRequester_YesNo) = 6
    bingo()
  EndIf
EndProcedure

If InitMouse()=0 Or InitSprite()=0 Or InitKeyboard()=0; Or InitPalette(10) = 0
  MessageRequester("Error", "Can't open DirectX 7", 0)
  End
EndIf

hWnd=OpenWindow(0,300,300,500,300,#PB_Window_SystemMenu|#PB_Window_TitleBar,"BINGO")
If hWnd=0
  MessageRequester("Error","Something fails",0)
  End
EndIf

If OpenWindowedScreen(hWnd,300,300,500,300,1,0,0)=0
  MessageRequester("Error","Something fails",0)
  End
EndIf

StartDrawing(WindowOutput()):DrawingMode(0)
bingo()
SAL:
StopDrawing()
CloseScreen() 
CloseWindow(0)
End
OpenWindowedScreen() function fails only sometimes when code is executed.
But if you replace the window handler for *hWnd, then all run fine every times you execute it.
Why? Could be a bug?
Fred
Administrator
Administrator
Posts: 18351
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

It almost not possible, as the '*' and long are the same. Try to the put a '.l' when defining your variable, but your bug is suspicious..
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Hi, Fred.

Ok, putting .l all seem to work all times correctly.

But why? It is supposed that until i call to the function the default type is long!
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Hmm, looks like not. See this short test:

Code: Select all

Procedure test()
  DefType.b
EndProcedure
a = 255
Debug a
If 'a' was a long, it would print 255, but it prints -1, because a is a byte.
Looks like DefType also is a compiletime thing, that doesn't care about
beeing inside a procedure.

Timo
quidquid Latine dictum sit altum videtur
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Exact Timo.

:lol:
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Post by oldefoxx »

I would like to throw in my two cents worth on this discussion: Type checking is often needed when locating obscure bugs in your code, because you are showing the compiler HOW you intend to use a given
variable, and based on that, the compiler can sport subtle errors where
a typed variable is being used in an unexpected manner (unexpected to
the compiler, that is).

When you dp not specify a type, you leave it to the compiler to make the decision for you. If by chance the compiler creates a BYTE type, and you later attempt to use the variable as a pointer, with a Long (32-bit) form, then you are in effect dereferencing what four consecutive bytes in memory might point to by chance. Lets say that you did assigned the following: a=123, then the compiler can, by rights, assume that a is a byte. If you then did a b=@a, then you would be in effect, attempting to use 123 ??? ??? ??? ( four consecutive bytes) as that memory address.

If, by chance, you had done this: a=278, then the compiler could have seen that you had to use some larger variable for (a byte can only go up to 255 in count). But now it could be a word. using b=@a would mean dereferencing (looking up the memory starting at giving address) where you would have 022 001 ??? ??? as the apparent memory reference. Note that for easier understanding, the byte values are given in decimal.

But again, this would be in error. Now, not having explored this yet on my own, I assume that such errors are possible. However, if you had forced a to a given type, by first using it as a.l=123 or *a=123, then you would have let the compiler know at that time that 4 bytes (32-bits) were the number of bits needed to represent a. The * format would have told the compiler that "since this is a pointer, then it is proper for it to use as a defererencing tool (to use with the @ symbol). That can help type usage enforcement. But even if a were defined as a long (a.l), the use of @a to dereference a memory address is permissable.

Now, having recognized the advantage of strong type checking, I do not agree that everyone needs to use this form, and PureBASIC allows you to go either way. Here is one reason why I feel as I do. If *a=0, then it represents the NULL character, string, or value sought after in certain situcations. NULL typically means "Undefined", or "I don't care what this parameter is" when passing it as part of a function call. If undefined, you might need to define it. If undefined, you might want to ignore it. But in a strong type checking environment, it may not be allowed to leave *a undefined or to attempt it to be equal to zero. You may not be able to do *a=0, for instance. Such checks do not occur on a.l, which initially is understood to have a value of 0 until assigned something else, and where a.l=0 is perfectly legal. So if the language was somewhat limited in its ability to handle NULL, and resisted allowing me to use *a=0, then I could do a a.l=0:b=@a and still enact a NULL-type capability.

I hope that makes sence, and that I am not in grevious error on how the PureBASIC compiler works in this respect.
has-been wanna-be (You may not agree with what I say, but it will make you think).
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

The Compiler never chooses the type for a variable on his own.
If you don't specify a type, it sets the default type, which is LONG.
You can change the default type by using the DefType command
without defining a variable. Like this:

DefType.b

Now each following Variable without a type will be of BYTE type.

So it is always the programmer, that sets the type, even if he doesn't
specify one. The compiler doesn't *assume* which type would be best.

Timo
quidquid Latine dictum sit altum videtur
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Type Setting

Post by oldefoxx »

Thanks for the correction. I haven't delved into PureBASIC enough to know these things -- after your first few languages, you then to just try to wing it with each new one, rather than really sit down with the manual. After your first few excursions in writing a program, you might then explore it further by manual (if there is one) to round out your knowledge (if the language looks like a good one, worthy of your time and effort).

So far, dispite the lack of any real documentation, I find PureBASIC interesting enough to spend some time with it. As to the pointer out-of-bounds explanation that I came up with, I don't really know if that is the case. it is just one more thing to explore and verity, and I just advanced that as a possibility that has to be checked for. Because of certain things I read on these forums, I judge that PureBASIC is a thin skin over FASM, and as a consequence, provides a lot of power, but may lack a little on the restraint side when it comes to getting out of bounds. And if there is anything to fear about getting out of bounds, it is the use of pointers!
has-been wanna-be (You may not agree with what I say, but it will make you think).
Post Reply