Sometimes when passing strings around, or mixing structured strings with normal strings, or using pointers, etc. the relationship between these different string representations may be confusing.
; a pb structured string is a structure like this
;
; Structure String
; s.s
; EndStructure
; when you modify the s.s string, its address @s may change, because the string contents are reallocated somewhere else if required
; the base address of the structure never change
; a normal unstructured a$ string it's actually stored inside a structure too but that structure is not visible
; again the address of this string may change when modified
; the base address of the "invisible" structure never change
; some pratical examples to explore these relationships (better go through them using the step debugger)
#SPACES = 64 ; this is to try to force a reallocation when updating the string, use a bigger number if required
; when using a structured string
Define a.string\s = "hello"
Debug @a ; base address of the PB string structure, the string is NOT in there, the structure contains just a pointer to the string
Debug @a\s ; this is the "PB way" to get the address of actual string
Debug PeekI(@a) ; this is equivalent to the above, you read the pointer located at the start of the structure
Debug a\s ; this is the "PB way" to print the string
Debug PeekS(@a\s) ; this is equivalent to the above
Debug PeekS(PeekI(@a)) ; and this too is equivalent to the above
a\s = a\s + Space(#SPACES) + "world" ; if you modify the string ...
Debug a\s ; string is changed
Debug @a\s ; ... you'll see the address of the string is probably changed, because a new allocated string replaced the old one
Debug @a ; ... while the address of the structured string is still the same
Debug "--------------------"
; when using a plain string
; the string it's still part of a structured PB string, but the structure it's not directly accessible
Define a$ = "hello"
Debug @a$ ; this is the address of the actual string
Debug a$ ; this prints the string
Debug PeekS(@a$) ; so this is equivalent to the above
a$ = a$ + Space(#SPACES) + "world" ; if you modify the string ...
Debug a$ ; string is changed
Debug @a$ ; ... you'll see the address of the string is probably changed, because a new allocated string replaced the old one
Debug PeekS(@a$) ; so this is equivalent to the above
; the base address of the structured string is not changed, but you can't access it anyway
; ... unless you use some asm
Define *p
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
! lea ecx,[v_a$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p], ecx ; and copies it to *p
CompilerElse
! lea rcx,[v_a$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p], rcx ; and copies it to *p
CompilerEndIf
Debug *p ; base address of the "invisible" PB string structure
Debug PeekI(*p) ; this is the pointer located at the start of the structure which points to a$
Debug PeekS(PeekI(*p)) ; and a$ contents are there
a$ = "hello"
*pp =@a$ ; you save in a pointer the address of the string, where the characters are stored ...
Debug @*pp ; you print the address of the pointer variable
Debug PeekI(@*pp) ; you read the value stored inside the pointer (what you saved with *pp=@a$), so the address of the string a$. PeekI(@*pp) is the same as *pp
Debug PeekS(PeekI(@*pp)) ; you print the contents of the string a$
In my asm code, I was getting the address of the "invisible" structure containing the string. And from there I was getting the address of the string to show it is indeed there.
It looks safe to swap 2 strings this way, however that's not much usable on practice (as different macro needed to be used from procedures and outside) + anyway "Swap" does that already.
Well maybe someone will find another usage, I currently have no better ideas ^^ (except some crazy stuff like following:)
EnableExplicit
; some dirty stuff
Define a$ = "1"
Define b$ = "2"
Define.Integer *p, *p1
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
! lea ecx,[v_a$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p], ecx ; and copies it to *p
CompilerElse
! lea rcx,[v_a$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p], rcx ; and copies it to *p
CompilerEndIf
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
! lea ecx,[v_b$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p1], ecx ; and copies it to *p
CompilerElse
! lea rcx,[v_b$] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p_p1], rcx ; and copies it to *p
CompilerEndIf
; now a$ and b$ using the same memory
*p\i = *p1\i
; thus changing a$ or b$ will change both of them
; that's so... thoughtful ^^
b$ = "asdffffffffffffff"
Debug a$
a$ = "sssssssss"
Debug b$
In practice copying one pointer to another makes one string an ALIAS to the other, hence you have ONE string with TWO different names.
BTW if we want to split hairs in half (just for completeness), it is probably nice to set to #Null$ the string you are about to unlink from its original memory area to deallocate it or you end up with some orphaned memory (the original a$ contents).
EnableExplicit
Macro GetStringStruct (a, p)
CompilerIf (#PB_Compiler_Processor = #PB_Processor_x86)
! lea ecx,[a] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p], ecx ; and copies it to *p
CompilerElse
! lea rcx,[a] ; this load the address of where the PB structured string containing a$ is in memory
! mov [p], rcx ; and copies it to *p
CompilerEndIf
EndMacro
Define a$ = "1"
Define b$ = "2"
Define.Integer *pa, *pb
GetStringStruct (v_a$,p_pa)
GetStringStruct (v_b$,p_pb)
Debug a$
Debug b$
a$ = #Null$ ; free the original contents of a$
; unlink a$ from its memory area and link it to b$
*pa\i = *pb\i
; now a$ is an alias to b$
Debug @a$
Debug @b$
b$ = "123"
Debug a$
a$ = "456"
Debug b$