Page 1 of 2

Getting address of string constants with @ or ?

Posted: Tue Aug 14, 2007 7:09 am
by technicorn
Hi,

it would be a nice feature to be able to get the address
of a string constant with the @ or ? operator,
so you could pass them to procedures by pointer for example.

Greatings
technicorn

edit:
Just found that you can take the address of a string constant,
but only for the string itself:

a=@"Hello" ; works
#const = "Hello"
a=@#const ; gives a syntax error

Posted: Tue Aug 14, 2007 1:00 pm
by Bonne_den_kule
The only intension with constants is to make the code easier to read/understand. The compiler replaces the constants in code with it's value before compiling.

Posted: Tue Aug 14, 2007 2:41 pm
by Kaeru Gaman
the adress of a constant? :shock:

Re: Getting address of string constants with @ or ?

Posted: Tue Aug 14, 2007 3:30 pm
by tinman
technicorn wrote:it would be a nice feature to be able to get the address
of a string constant with the @ or ? operator,
so you could pass them to procedures by pointer for example.
Until it does you could always use a macro instead of constants for strings:

Code: Select all

Macro const
"Hello"
EndMacro

Procedure.l StrAdr(addr.l)
    ProcedureReturn addr
EndProcedure

Debug StrAdr(@"Hello")
Debug StrAdr(@const)

End

Posted: Tue Aug 14, 2007 7:08 pm
by technicorn
Thanks tinmann,
but that doesn't help me with my problem.

To make clear what my intention was for this request,
I want to write a program that keeps track of which file and line a procedure is called from.

For lines that is simple, because #PB_Compiler_Line is a numeric constant,
And for the filename you can use #PB_Compiler_File , but it will give you a string,
which isn't very usefull, because stringhandling is to slow,
just having the address of that constant is much easier to handle and
is as unique as the string itself.

But you can't use @ or ? with #PB_Compiler_File, it will give syntax error.

Hope that makes it clearer.

Posted: Tue Aug 14, 2007 7:21 pm
by ts-soft
There is no adress to a stringconstant, the compiler sets the string direct. For this are Constants.

Re: Getting address of string constants with @ or ?

Posted: Tue Aug 14, 2007 8:24 pm
by helpy
Hi technicorn,
technicorn wrote:it would be a nice feature to be able to get the address
of a string constant with the @ or ? operator,
so you could pass them to procedures by pointer for example.
If you want to use string constants, than use DataSection!

cu, helpy

Posted: Tue Aug 14, 2007 9:14 pm
by technicorn
@ts-soft

There is an address, see this:

Main file "StringConstants_test.pb"

Code: Select all

Define file1.s, file2.s

file1 = #PB_Compiler_File
XIncludeFile "StringConstants.pbi"
MessageRequester("Test", file1+#LF$+file2)
Include file "StringConstants.pbi"

Code: Select all

file2 = #PB_Compiler_File
Excerpt of the resulting asm file compiled with /COMMENTED:

Program part:
; Define file1.s, file2.s
;
; file1 = #PB_Compiler_File
MOV edx,_S1
LEA ecx,[v_file1]
CALL SYS_FastAllocateStringFree
; XIncludeFile "StringConstants.pbi"
; file2 = #PB_Compiler_File
MOV edx,_S2
LEA ecx,[v_file2]
CALL SYS_FastAllocateStringFree
;
; MessageRequester("Test", file1+#LF$+file2)
PUSH dword [_PB_StringBasePosition]
MOV edx,dword [v_file1]
PUSH dword [_PB_StringBasePosition]
CALL _SYS_CopyString@0
MOV edx,_S3
CALL _SYS_CopyString@0
MOV edx,dword [v_file2]
CALL _SYS_CopyString@0
INC dword [_PB_StringBasePosition]
PUSH dword _S4
MOV edx,[PB_StringBase]
ADD [esp+4],edx
CALL _PB_MessageRequester@8
POP dword [_PB_StringBasePosition]

Data part:
public _SYS_StaticStringStart
_SYS_StaticStringStart:
_S1: db "StringConstants_Test.pb",0
_S2: db "G:\Projects\PureBasic4\Tests\StringConstants.pbi",0
_S3: db 10,0
_S4: db "Test",0
pb_public PB_NullString
db 0
public _SYS_StaticStringEnd

As you can see, _S1, _S2 are the addresses for the different replacements of #PB_Compiler_File,
_S3 is the #LF$
and _S4 is for the "Test" string used by the MessageRequester

@helpy
Sorry, but that will not solve my problem,
even using a seperate DataSection for the main and every included source
would mean, you have to give different names to labels in the DataSection,
so you can not use a simple construct like this:

TestProc(param1, param2, ..., @#PB_Compiler_File, #PB_Compiler_Line)

so that TestProc() would get it's normal parameter and the pointer to
the filename string that it was called from.
Of course I would use a Macro to call TestProc() which will be replaced
by just the normal call of TestProc() and parameters, without the filename and linenumber in the final application compilation.

I'm asking for this feature, because I want to write a library written in
pure PB (no asm) to keep track of pointer allocation/reallocation/freeing
with the PB functions AllocateMemory() and the like,
because I often use pointers in my programs and I want to make life easier by knowing where the pointer was used last time.

I already have a set of functions that keep track of that, but I want to store the filenames and linenumers with it,
to make it easier to track errors down to the root.

Sorry if that all sounds like rambling to someone else,
maybe it's just importend to me, and I have to find my
one way to solve that problem.

CU
technicorn

Posted: Tue Aug 14, 2007 9:23 pm
by ts-soft
Can't see any stringconstant, file1 and file2 are variables stored in datasection

Posted: Tue Aug 14, 2007 9:56 pm
by tinman
How about this then? It seems to work for me, at least the value I get from the two debug statements are the same. You need to watch that you use the correct pseudotype for the string parameter otherwise PB will convert it and cause the address to be different.

I guess if this is going to be part of your own debug logging library you should be able to hide most of this hackery behind a macro in another file or something.

Code: Select all

Prototype.l StrCheat(sring.p-unicode)

Procedure.l StrAddr(str_addr.l)
    ProcedureReturn str_addr
EndProcedure

*foo.StrCheat = @StrAddr()
#const = "Foo"
Debug *foo(#const)
Debug @"Foo"
End
Obviously the best solution would be for the compiler to accept @#const, which seems reasonable if #const is supposed to be replaced with "string" during compilation.

Posted: Tue Aug 14, 2007 10:37 pm
by technicorn
Thanks a lot tinman!! :D
I would have never thought of "miss"-using pseudotypes that way.

Some little enhancement to show it really works:

Code: Select all

CompilerIf #PB_Compiler_Unicode
  Prototype.l StrCheat(sring.p-unicode)
CompilerElse
  Prototype.l StrCheat(sring.p-ascii)
CompilerEndIf

Procedure.l StrAddr(str_addr.l)
    ProcedureReturn str_addr
EndProcedure

*foo.StrCheat = @StrAddr()
#const = "Foo"
*p1= *foo(#PB_Compiler_File)
*p2= *foo(#PB_Compiler_File)
Debug *p1
Debug *p2
Debug PeekS(*p1)
Debug PeekS(*p2)
Debug #PB_Compiler_File
End
I can life with the small overhead of the procedure call for now,
as it is only used in testing mode of the program.

Posted: Fri Aug 17, 2007 4:54 pm
by Trond

Code: Select all

Get the address of the file name string:
Debug ?PB_Compiler_File

; Put at the end of every file:
DataSection
  PB_Compiler_File:
  Data.s #PB_Compiler_File
EndDataSection
Disadvantage: The string for the filename will be included in the final executable. This should be obvious, though (if it wasn't included you wouldn't be able to get its address, right).

Posted: Fri Aug 17, 2007 8:58 pm
by technicorn
Hi Trond,

and what about duplicate labels? :twisted:

And no, I can't use different labels for each file,
because that would break the automatic insertion of the right name/label!

But thanks for trying to help.

technicorn

Posted: Fri Aug 17, 2007 9:48 pm
by Trond
Sorry. This ought to do the trick:

Code: Select all

Procedure Callback(FileAddress.l)
  Debug PeekL(FileAddress) ; Guaranteed to be different for each file
  Debug PeekS(PeekL(@FileAddress))
EndProcedure

Prototype ProtoCallbackInterface(FileAddress.s)

Function.ProtoCallbackInterface = @Callback()

Function(#PB_Compiler_File)

Posted: Sat Aug 18, 2007 3:04 pm
by tinman
Trond wrote:Sorry. This ought to do the trick:
Except that it doesn't because PB is still copying your string to a local variable before you get the address. Check out your code using this:

Code: Select all

string.s = "bar"
Debug @string
Function(string)
Using the pseudotypes works because PB doesn't perform any copying - the pseudotype is for external functions that take a string pointer.