Announcement

Collapse
No announcement yet.

how do i use a string pointer when calling/using a function

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Bob Zale
    replied
    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,

    Leave a comment:


  • Paul Purvis
    replied
    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:


  • Michael Mattias
    replied
    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


    MCM
    Last edited by Michael Mattias; 1 May 2008, 06:02 PM.

    Leave a comment:


  • John Gleason
    replied
    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:


  • Michael Mattias
    replied
    If an ASCIIZ or a Fixed-Length string, you'll just read garbage
    ...or induce a General Protection Fault...(depending on from where / how you allocated the string)...

    Leave a comment:


  • Michael Mattias
    replied
    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:


  • John Gleason
    replied
    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:


  • Paul Purvis
    replied
    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))
    thanks again for help
    paul
    Last edited by Paul Purvis; 30 Apr 2008, 04:35 AM.

    Leave a comment:


  • Chris Holbrook
    replied
    Originally posted by Bob Zale View Post
    .. you'll just read garbage.
    Or even memory which you don't own?

    Leave a comment:


  • Bob Zale
    replied
    Originally posted by John Gleason View Post
    Yes there is a way--it's the 4 bytes before the string data.
    Remember, that only works if it's a dynamic string. If an ASCIIZ or a Fixed-Length string, you'll just read garbage.

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Adam J. Drake
    replied
    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
    Or if you need more speed, use ASM:

    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:


  • John Gleason
    replied
    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
    Yes there is a way--it's the 4 bytes before the dynamic string data. I've shown an example below. Borrowed from Adam btw, ty Adam.
    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
    Last edited by John Gleason; 30 Apr 2008, 06:49 AM. Reason: added that this is for dynamic strings

    Leave a comment:


  • Adam J. Drake
    replied
    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 would perfer to work on the string in the function without having to create a variable byte ptr using strptr(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$))
    thanks
    paul
    Last edited by Paul Purvis; 29 Apr 2008, 09:23 PM.
Working...
X