Page 1 of 1

Structured strings and plain strings

Posted: Thu Jun 22, 2017 2:37 pm
by luis
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.

Maybe this can be of some help to someone.

Code: Select all

; 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


Re: Structured strings and plain strings

Posted: Thu Jun 22, 2017 5:24 pm
by Kwai chang caine
A very good and precious explanation about string :shock:
Need for me, several days of thinking :mrgreen:
Thanks for sharing 8)

Re: Structured strings and plain strings

Posted: Thu Jun 22, 2017 7:39 pm
by davido
@luis,
Excellent. Thank you for the explanation.
Always nice to learn something new.

Your input into this Forum is always welcome, in my humble opinion.

Re: Structured strings and plain strings

Posted: Thu Jun 22, 2017 10:28 pm
by Wolfram
Thanks for this example.
I just stumbled on the problem yesterday.

Is your assambler code faster as this?

Code: Select all

*pp =@a$
*p =@*pp
Debug *p
Debug PeekI(*p)
Debug PeekS(PeekI(*p))

Re: Structured strings and plain strings

Posted: Thu Jun 22, 2017 11:00 pm
by luis
@KCC, @Davido :wink:
Wolfram wrote:Thanks for this example.
I just stumbled on the problem yesterday.
That's why I posted this, and because I remembered these things are asked from time to time :)

About your question....

Uhm.. but my little asm code does an entirely different thing (?)

I'm not sure what's the purpose of your code.

Code: Select all

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.

Re: Structured strings and plain strings

Posted: Fri Jun 23, 2017 1:28 am
by Lunasole
Thanks for some interesting ASM magic

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:)

Code: Select all

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$

Re: Structured strings and plain strings

Posted: Fri Jun 23, 2017 10:53 am
by luis
@Lunasole

ahahah I like your idea :wink:

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).

Code: Select all

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$

Re: Structured strings and plain strings

Posted: Sun Jun 25, 2017 12:47 pm
by mk-soft
We can“t for procedures a string as argument byref, only with structure types, because the pointer to the string is change.

Edit

Code: Select all

;-TOP
Procedure foo(*inout.String, *value.integer)
  *inout\s + " 12345678"
  *value\i + 100
EndProcedure

Global t1.String
Global v1 = 100
t1\s = "hello world"
Debug PeekI(t1)
Debug PeekS(PeekI(t1))
foo(t1, @v1)
Debug PeekI(t1)
Debug PeekS(PeekI(t1))
Debug v1
See a way or features request