Paul--
The descriptions you posted describe a file format or the contents of a particular string created for a specific purpose. That's very different from describing the way PowerBASIC keeps track of a variable in memory. There is no connection between the two concepts.
Given that one has a pointer to some string data, somewhere in memory, there is no way to know the length of the data, in all cases, with certainty. No way.
You are, in a sense, trying to "trick" PowerBASIC into passing some data in a non-standard way, because it may appear to be better or more efficient. It isn't better. {smile}
The easiest way to do what you want is to pass the string as a standard parameter, probably ByRef. Then PowerBASIC provides you with anything you need about the data.
Best regards,
Bob Zale
PowerBASIC Inc,
Announcement
Collapse
No announcement yet.
how do i use a string pointer when calling/using a function
Collapse
X
-
in pb console compiler and i presume also in windows compiler there is a mention of string lengths and having to 2 bytes to hold the string length,
i am not sure whether a string header of two bytes with a possiblity of 4 bytes is only for arrays of dynamic strings or for all dynamic strings.
these lines of notes came from the help section, just do a search for "65535".
i am just wanting to point out the string lengths and 2 byte lengths.
maybe somebody has a take on this subject.
JOIN$ function has been enhanced with a BINARY option. If the array consists of fixed size elements ( , ASCIIZ, etc.), the returned consists of an exact memory image of the array data in internal format. If the array contains variable length data (Dynamic string, Field string), it is stored in PowerBASIC and/or Visual Basic packed string format: If a string is shorter than 65535 bytes, it starts with a 2-byte length WORD followed by the string data. Otherwise it will start a 2-byte value of 65535, followed by a DWORD indicating the string length, then finally the string data itself.
FILESCAN statement
Purpose
Rapidly scan a file opened for INPUT or BINARY mode, in order to obtain size information about variable length string data.
Syntax
FILESCAN [#] fnum&, RECORDS TO y& [, WIDTH TO x&]
Remarks
FILESCAN assigns a count of the lines/records/strings to y&, and if the WIDTH clause is specified, the length of the longest string to x&.
In INPUT mode, it is assumed the data is standard text, with lines delimited by a CR/LF ($CRLF) pair. FILESCAN stops reading the file if it encounters an "end of file" (EOF) marker byte (CHR$(26) or $EOF). Text that occurs after the last CR/LF but before the EOF is considered the last record of the file. Use the LINE INPUT# statement to read a complete text file into an array.
In BINARY mode, it is assumed the file was written in the PowerBASIC and/or VB packed string format using PUT of an entire string array. If a string is shorter than 65535 bytes, a 2-byte length WORD is followed by the string data. If a string is equal to or longer than 65535 bytes, a 2-byte value of 65535 is followed by a length DWORD value, then finally the string data.
PARSE statement
Purpose
Parse an entire and extract all delimited fields into an array.
Syntax
PARSE main$, array$() [, {[ANY] delim$ | BINARY}]
Remarks
PARSE parses the entire string or string expression specified by main$, assigning each delimited sub-string to successive elements of array$. The array specified by array$ may be a dynamic string array, a fixed-length string array, an ASCIIZ string array, or a .
The field delimiter is defined by delim$, which may be one or more characters long. To be valid, the entire delimiter must match exactly, but the delimiter itself is never assigned as a part of the delimited field.
If delim$ is not specified or is null (zero-length), standard comma-delimited (optionally quoted) fields are presumed. In this case only, the following parsing rules apply. If a standard field is enclosed in optional quotes, they are removed. If any characters appear between a quoted field and the next comma delimiter, they are discarded. If no leading quote is found, any leading or trailing blank spaces are trimmed before the field is returned.
ANY
If the ANY option is chosen, each appearance of any single character comprising delim$ is considered a valid delimiter.
BINARY
The BINARY option presumes that the string_expr was created with the JOIN$/BINARY function, or its equivalent, which creates a string as a binary image or in the PowerBASIC and/or Visual Basic packed string format: If a string is shorter than 65535 bytes, it starts with a 2-byte length WORD followed by the string data. Otherwise it will start a 2-byte value of 65535, followed by a DWORD indicating the string length, then finally the string data itself.Last edited by Paul Purvis; 1 May 2008, 08:30 PM.
Leave a comment:
-
If the (ASCIIZ) string is allocated from the far heap, there's a "good chance" (but not certainty!) the preceding four bytes are in 'no man's land' and you will get an immediate protection fault.
All PB ASCIIZ variables (LOCAL, STATIC and GLOBAL) are allocated from the stack or your program's data segment, so it's likely you own that memory and therefore may read or write it ... except when you read/write it, you are not reading/writing a string length, you are read/writing either one of your program's OTHER variables and/or a return address on the stack.
FWIW, I think you can stil blow out the stack and get a GPF by allocating an ASCIIZ larger than the default stack size:
Code:FUNCTION PBMAIN() AS LONG LOCAL Z AS ASCIIZ * 2000000 ' 2 million Z = "Z" FUNCTION = 5 END FUNCTION
MCMLast edited by Michael Mattias; 1 May 2008, 06:02 PM.
Leave a comment:
-
I was wondering about the GPF vs. reading garbage question, so I tried to get a GPF by PEEKing the 4 bytes prior to various fixed and asciiz strings and arrays. I wouldn't normally code something like this intentionally, but it could probably happen by accident (by accident just about every nasty thing that can be coded has been coded), so I tested it in the code below, but never got a GPF. Does anyone have code showing that reading those 4-bytes can GPF?
Code:#COMPILE EXE #DIM ALL GLOBAL gAz AS ASCIIZ * 99 GLOBAL gFs AS STRING * 79 FUNCTION PBMAIN () AS LONG LOCAL sz AS ASCIIZ * 632, szPtr AS LONG PTR LOCAL ii, x, r AS LONG CALL t1 CALL t2 FOR ii = 1 TO 1000000 REDIM arrX(5) AS STRING * 63 REDIM arrZ(5) AS ASCIIZ * 31 sz = STRING$(RND(11, 631), 52) szPtr = VARPTR(sz) - 4 x = PEEK (LONG, szPtr) gaz = STRING$(RND(1, 98), 22) szPtr = VARPTR(gaz) - 4 x = PEEK (LONG, szPtr) gfs = STRING$(RND(1, 79), 30) szPtr = VARPTR(gfs) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrX(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrZ(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) NEXT ? "k, no gpfs in any of these situations" END FUNCTION SUB t1() LOCAL sz AS ASCIIZ * 632, szPtr AS LONG PTR LOCAL ii, x, r AS LONG FOR ii = 1 TO 1000000 REDIM arrX(5) AS STRING * 63 REDIM arrZ(5) AS ASCIIZ * 31 sz = STRING$(RND(11, 631), 52) szPtr = VARPTR(sz) - 4 x = PEEK (LONG, szPtr) gaz = STRING$(RND(1, 98), 22) szPtr = VARPTR(gaz) - 4 x = PEEK (LONG, szPtr) gfs = STRING$(RND(1, 79), 30) szPtr = VARPTR(gfs) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrX(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrZ(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) NEXT ? "k, no sub gpf" END SUB FUNCTION t2() AS LONG LOCAL sz AS ASCIIZ * 632, szPtr AS LONG PTR LOCAL ii, x, r AS LONG FOR ii = 1 TO 1000000 REDIM arrX(5) AS STRING * 63 REDIM arrZ(5) AS ASCIIZ * 31 sz = STRING$(RND(11, 631), 52) szPtr = VARPTR(sz) - 4 x = PEEK (LONG, szPtr) gaz = STRING$(RND(1, 98), 22) szPtr = VARPTR(gaz) - 4 x = PEEK (LONG, szPtr) gfs = STRING$(RND(1, 79), 30) szPtr = VARPTR(gfs) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrX(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) szPtr = VARPTR(arrZ(RND(0, 5))) - 4 x = PEEK (LONG, szPtr) NEXT ? "k, no function gpf" END FUNCTION
Leave a comment:
-
If an ASCIIZ or a Fixed-Length string, you'll just read garbage
Leave a comment:
-
Why not just pass it in code as a [BYREF] STRING?
Then the compiler will handle all that icky pointer stuff for you.
Leave a comment:
-
Yes indeed, the above technique I show applies to only dynamic strings. I updated the comments to reflect that.
Also Paul, GOSUB I have to believe would boost speed, because it is lean and fast.
Leave a comment:
-
thanks for those timely answers
Adam, i was so sure that your code was going to improve the speed of the number to string routine i had created, but, surprising, the poke with the byte was faster, at least that is what showed in my results.
i would of figured @temp[i]=37 would beat hands down a statement of PEEK BYTE temp, 37 on speed. i have seen this another time using the PEEK QUAD statement.
thanks for posting that code, i just could not get it down on how to do it and your example was a good clean example of what i needed.
i will have to try the sub, i did not think about that, i did a gosub and it increased my speed by about a third in reduction of time.
John i will test that an get back to you on the number2string function to see if increases the speed, it would definitely be cleaner and less errors in programming code using that technique in a function.
Bob thanks for reminding us of that fact, a note of that point reminding to use only dynamic strings would go well in the number2string function.
i ended up using something like this.
Code:FUNCTION functiona(BYVAL STRLEN AS LONG, BYREF ptrss AS LONG ) AS STRING LOCAL I AS LONG for I=0 to STRLEN-1 POKE BYTE,ptrss+I,37 next I end function ' main code in program SS=SPACE$(25) functiona(25,STRPTR(SS))
paulLast edited by Paul Purvis; 30 Apr 2008, 04:35 AM.
Leave a comment:
-
Originally posted by Bob Zale View Post.. you'll just read garbage.
Leave a comment:
-
Want to get even faster?
Use a SUB instead of a function:
Code:#COMPILE EXE #DIM ALL SUB SubA(BYVAL temp AS BYTE PTR) LOCAL i AS LONG LOCAL templen AS LONG templen = PEEK(LONG, temp - 4) FOR i = 0 TO templen @temp[i] = 37 NEXT END SUB FUNCTION PBMAIN () AS LONG LOCAL temp AS STRING LOCAL s, f AS SINGLE LOCAL x, y AS LONG MSGBOX "Temp: " + temp temp = SPACE$(25) s = TIMER y = STRPTR(temp) FOR x = 1 TO 10000000 CALL SubA(BYVAL y) NEXT f = TIMER MSGBOX "Temp: " + temp + $CRLF + _ "Elapsed: " + FORMAT$(f - s) END FUNCTION
Code:SUB SubA(BYVAL temp AS BYTE PTR) #REGISTER NONE !pushad !mov eax, temp !mov ebx, eax !sub eax, 4 !mov ecx, [eax] !xor edx, edx LoopLabel: !mov dl, 37 !mov [ebx], dl !inc ebx !dec ecx !cmp ecx, 0 !jne LoopLabel !popad END SUB
Last edited by Adam J. Drake; 30 Apr 2008, 12:44 AM.
Leave a comment:
-
another question
if i pass a string as a pointer, can i easily get the length of the string inside the function, this would keep me from having to passing the length of the string at the call to the function
Code:#COMPILE EXE #DIM ALL FUNCTION FunctionA(BYVAL temp AS BYTE PTR, templen AS LONG) AS LONG LOCAL i AS LONG FOR i = 0 TO templen @temp[i] = 37 NEXT END FUNCTION FUNCTION FunctionB(BYVAL temp AS BYTE PTR) AS LONG LOCAL i AS LONG LOCAL tempLen AS LONG tempLen = PEEK(LONG, temp - 4) 'dynamic string length is the LONG 4 bytes just before the string data FOR i = 0 TO templen @temp[i] = 37 NEXT END FUNCTION FUNCTION PBMAIN () AS LONG LOCAL temp AS STRING LOCAL s, f AS SINGLE LOCAL x, y, z AS LONG MSGBOX "Temp: " + temp temp = SPACE$(25) s = TIMER y = STRPTR(temp) FOR x = 1 TO 10000000 ' FunctionA(BYVAL STRPTR(temp), LEN(temp) - 1) FunctionB(y) '31% faster than functionA NEXT f = TIMER MSGBOX "Temp: " + temp + $CRLF + _ "Elapsed: " + FORMAT$(f - s) END FUNCTION
Leave a comment:
-
If you pass just the pointer, I am not aware of a way to get the string length. If you know the ASC value of the byte you want to insert into the string, it is much quicker to just use numbers, instead of the ASC function.
One million calls to that function on my machine goes from .54 seconds, to .14 seconds with the code changes below:
Code:#COMPILE EXE #DIM ALL FUNCTION FunctionA(BYVAL temp AS BYTE PTR, templen AS LONG) AS LONG LOCAL i AS LONG FOR i = 0 TO templen @temp[i] = 37 NEXT END FUNCTION FUNCTION PBMAIN () AS LONG LOCAL temp AS STRING LOCAL s, f AS SINGLE LOCAL x AS LONG MSGBOX "Temp: " + temp temp = SPACE$(25) s = TIMER FOR x = 1 TO 1000000 FunctionA(BYVAL STRPTR(temp), LEN(temp) - 1) NEXT f = TIMER MSGBOX "Temp: " + temp + $CRLF + _ "Elapsed: " + FORMAT$(f - s) END FUNCTION
Leave a comment:
-
how do i use a string pointer when calling/using a function
my problem is passing a string pointer to a function
here is what i want to do,
assign a variable string so many x spaces prior to calling function
call a function
have the function work on the string using the pointer
return from the function
as shown below, the method i have now is slow, probably has something to do with the stack, i do not know
Code:the function: functiona(byref temp$ as string) local i as long local ptrtemp as byte ptr ptrtemp=strptr(temp$) for i=0 to len(temp$)-1 poke byte,ptrtemp+i,asc("%") next i end function the code in main program: temp$=space$(25) functiona(temp$)
i am not sure if calling the function with a pointer instead of using byref but i feel it would be faster
another question
if i pass a string as a pointer, can i easily get the length of the string inside the function, this would keep me from having to passing the length of the string at the call to the function
i want something like this, if it would help speed thing up, i am sure my codeing will not be right calling the function, that is where i need help
Code:the function: functionb(byref ptrtemp as pointer) local i as long local j as long j=len(ptrtemp) for i=0 to j-1 poke byte,ptrtemp+i,asc("%") next i end function the code in the main program: temp$=space$(25) functionb(strptr(temp$))
paulLast edited by Paul Purvis; 29 Apr 2008, 09:23 PM.Tags: None
Leave a comment: