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

  • 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.
    p purvis

  • #2
    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
    Adam Drake
    Drake Software

    Comment


    • #3
      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

      Comment


      • #4
        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.
        Adam Drake
        Drake Software

        Comment


        • #5
          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.

          Comment


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

            Comment


            • #7
              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.
              p purvis

              Comment


              • #8
                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.

                Comment


                • #9
                  Why not just pass it in code as a [BYREF] STRING?

                  Then the compiler will handle all that icky pointer stuff for you.
                  Michael Mattias
                  Tal Systems Inc. (retired)
                  Racine WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    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)...
                    Michael Mattias
                    Tal Systems Inc. (retired)
                    Racine WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      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

                      Comment


                      • #12
                        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.
                        Michael Mattias
                        Tal Systems Inc. (retired)
                        Racine WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          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.
                          p purvis

                          Comment


                          • #14
                            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,

                            Comment

                            Working...
                            X