Passing fixed-len string as arguments: possible but not recommended?

General FreeBASIC programming questions.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Passing fixed-len string as arguments: possible but not recommended?

Post by Tourist Trap »

Hello,

this is not clear what syntax may be used to pass zstring*n stuff or similar (string*n).

Code: Select all

sub X(byval S as zstring*6)
    ? S
end sub

X(cast(zstring*6, "abc"))
error 59: Illegal specification, at parameter 1 (S) of X() in 'sub X(byval S as zstring*6)'
I found nothing in the doc at zstring page or function page (only zstring ptr is cited), as well as for returning stuff as fixed-len strings.

Code: Select all

function X(byval S as zstring*6) as zstring*6
    return S
end function

? X(cast(zstring*6, "abc"))
error 59: Illegal specification, at parameter 1 (S) of X() in 'function X(byval S as zstring*6) as zstring*6'
error 181: Invalid assignment/conversion in 'return S'
Do somebody can kindly tell us more about all of this?
Thank you.
Last edited by Tourist Trap on Dec 15, 2018 13:09, edited 1 time in total.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Passing fixed-len string as arguments impossible?

Post by fxm »

- A 'String * n' (fixed-length string) argument can only be passed to a procedure as a '[Byval/Byref] As String' (variable-length string) parameter.
- A 'Zstring * n' argument can only be passed to a procedure as a '[Byval/Byref] As Zstring Ptr' or '[Byref] As Zstring' parameter .
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Passing fixed-len string as arguments impossible?

Post by Tourist Trap »

fxm wrote:- A 'String * n' (fixed-length string) argument can only be passed to a procedure as a '[Byval/Byref] As String' (variable-length string) parameter.
Hi fxm, thanks for clarification. Edit: ok misread.
fxm wrote: - A 'Zstring * n' argument can only be passed to a procedure as a '[Byval/Byref] As Zstring Ptr' or as a '[Byref] As Zstring' parameter .
This is a thing that I've acquired an intuition of with the time, by reading the codes posted here and here. However, that's not really clear in the documentation. I don't know if I'm right, but it seems that the general philosophy with zstrings is to use them as zstring ptr. Then zstring*n are possible but with a usage that is similar to string*n but not equal. This comparison between zstring*n and string*n is not obvious.

Maybe there are not so much differences as I couldn't pass neither a zstring*n nor a string*n to as sub for the moment.
If we can pass string*n however, this starts to be really different than zstring*n. (useless remark from my first misread)

What is the general philosophy in the choice between zstring ptr, zstring*n, string*n, string? Should we consider that only zstring ptr and string are for normal usage in FB, and the other stuff for compatibility? I dont know.

As a remark, I already know that fixed length strings are mandatory in unions where it would be very different to use a pointer.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Passing fixed-len string as arguments impossible?

Post by fxm »

fxm wrote:- A 'Zstring * n' argument can only be passed to a procedure as a '[Byval/Byref] As Zstring Ptr' or '[Byref] As Zstring' parameter .
I quoted these two types of passage only to illustrate the possible syntaxes, but functionally they are equivalent because, under the hood, when we pass a variable by reference, in fact an internal pointer is passed (by value) and it is the compiler that dereferences implicitly this passed internal pointer (similarly when a function returns by reference).
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Passing fixed-len string as arguments impossible?

Post by Tourist Trap »

fxm wrote:
fxm wrote:- A 'Zstring * n' argument can only be passed to a procedure as a '[Byval/Byref] As Zstring Ptr' or '[Byref] As Zstring' parameter .
I quoted these two types of passage only to illustrate the possible syntaxes, but functionally they are equivalent because, under the hood, when we pass a variable by reference, in fact an internal pointer is passed (by value) and it is the compiler that dereferences implicitly this passed internal pointer (similarly when a function returns by reference).
Hi fxm,

Thanks. If we pass the zstring this way: BYREF AS ZSTRING, don't we loose the information on the size ? This example seems to show that we have no more a zstring*2 after X has been called.

Code: Select all

sub X(byref Zs as zstring)
    Zs = "abcdef"
end sub

dim as zstring*2 zstr
zstr = "abc"

? zstr      'returns a, as expected

X(zstr)
? zstr      'returns abcdef!!!
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Passing fixed-len string as arguments impossible?

Post by fxm »

Yes, the declared size for the zstring (used for memory allocation) is lost.
Therefore, if the procedure writes more characters than this declared value (as in your example above), the program may crash (by writing outside the allocated memory).
mrminecrafttnt
Posts: 131
Joined: Feb 11, 2013 12:23

Re: Passing fixed-len string as arguments impossible?

Post by mrminecrafttnt »

It's not supported..

Code: Select all

declare sub test (x as zstring * 6)
gives me
error 323: Fixed-length string combined with BYREF (not supported), before ')' in 'declare sub test (x as zstring * 6)
you have to write your own routines... ;)
You ive did this for you.
It's not perfect but it sill works ;)

Code: Select all



type autofixing_zstring
    d as zstring ptr
    declare destructor
    declare sub write_zstring(s as zstring)
    declare function read_zstring as zstring ptr
end type


destructor autofixing_zstring
    deallocate(d)
end destructor

sub autofixing_zstring.write_zstring (s as zstring)
    d = allocate(len(s))
    *d = s
end sub

function autofixing_zstring.read_zstring as zstring ptr
    return d
end function

'example starts here

sub print_zstring (s as zstring ptr)
    if len(*s) <> 11 then print "UNEXEPTED STRING SIZE, MODIFIED?" : EXIT SUB ' AN EXAMPLE TO DETECT BAD SIZE..
    print *s
end sub

dim as autofixing_zstring example
example.write_zstring ("HELLO WORLD")
print_zstring (example.read_zstring)


sleep


Boris the Old
Posts: 139
Joined: Feb 04, 2011 20:34
Location: Ontario, Canada

Re: Passing fixed-len string as arguments impossible?

Post by Boris the Old »

I would suggest that fixed length string/zstring data not be used in FB code, except where it's necessary for communicating with the outside world. It's too easy to write data outside the limits of the fixed string fields, or attempt to do things that are not supported.

We use FLTK, which requires zstring data for calls to the FLTK code. But we isolate the FLTK calls inside a single module that all our other code uses. Calls into, and out of, our FLTK wrapper use dynamic strings. Similarly, when reading records, the fixed length record fields are converted to dynamic strings for internal processing. We do the reverse conversion when writing file records. And as with FLTK, all file I/O goes through a single module.

In this way, our 1 million lines of application code need only know about dynamic strings, which are safer and easier to use. This approach to coding also make applications easier to code and maintain.

Rod
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Passing fixed-len string as arguments impossible?

Post by Tourist Trap »

mrminecrafttnt wrote: you have to write your own routines... ;)

Code: Select all

type autofixing_zstring
    d as zstring ptr
    declare destructor
    declare sub write_zstring(s as zstring)
    declare function read_zstring as zstring ptr
end type
Hi mrminecrafttnt,
I would rather suggest something like this:
(after some edit, operator LET was missing, and so on...)

Code: Select all

type FIXEDLENSTR
    declare operator cast() as string
    declare operator let(as string)
    as integer  slen
    as string   s
end type
operator FIXEDLENSTR.cast() as  string
    return left(THIS.s, THIS.slen)
end operator
operator FIXEDLENSTR.let(S as  string)
    THIS.s = left(S, THIS.slen)
end operator

sub Test (byref x as FIXEDLENSTR)
    x = "adjdssze"
end sub

dim as FIXEDLENSTR fls
fls.slen = 2
fls.s = "hello"

Test(fls)
? fls
Last edited by Tourist Trap on Dec 15, 2018 14:21, edited 2 times in total.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Passing fixed-len string as arguments impossible?

Post by Tourist Trap »

Boris the Old wrote:I would suggest that fixed length string/zstring data not be used in FB code, except where it's necessary for communicating with the outside world. It's too easy to write data outside the limits of the fixed string fields, or attempt to do things that are not supported.
Thank you, it's what needed to know. The intuition tends to tell us that fixed-length stuff will be easier and at least natural to handle, so it's good to be warned that it wont be so in FB.
fxm wrote:Yes, the declared size for the zstring (used for memory allocation) is lost.
Therefore, if the procedure writes more characters than this declared value (as in your example above), the program may crash (by writing outside the allocated memory).
Do you know if it is a temporary state, or something voluntarily for some expert reasons?
Boris the Old
Posts: 139
Joined: Feb 04, 2011 20:34
Location: Ontario, Canada

Re: Passing fixed-len string as arguments: possible but not recommended?

Post by Boris the Old »

As it stands, "fixed length string" support in FB is non-existent. It is the one big failing of FB.

For the past few years I've been looking around for a single language that will replace our current languages - COBOL, PowerBasic, and Assembler (that's what old guys call Assembly). We write business software, but also do a lot of low-level coding for our in-house database software.

The two important things missing from FB are: true fixed strings, and support for decimal arithmetic (floating point just isn't acceptable for business calculations). Everything else about FB is just fine. Luckily, we've been able to get around both problems by writing our own code. We use byte arrays to represent fixed strings, and manipulate them using a few short routines. Similarly, for decimal arithmetic support we've written our own math functions.

Rod
Carlos Herrera
Posts: 82
Joined: Nov 28, 2011 13:29
Location: Dictatorship

Re: Passing fixed-len string as arguments: possible but not recommended?

Post by Carlos Herrera »

Boris the Old wrote: ... support for decimal arithmetic (floating point just isn't acceptable for business calculations)...
What's wrong with floating point in FB? Could you be more specific?
Carlos
lizard
Posts: 440
Joined: Oct 17, 2017 11:35
Location: Germany

Re: Passing fixed-len string as arguments: possible but not recommended?

Post by lizard »

Carlos Herrera wrote: What's wrong with floating point in FB? Could you be more specific?
Carlos
Was to Boris, but i want to mention this:

Not only in FB. It is floating point in financial calculations, Rounding is a no-go there, because there exists only whole dollars, cents, etc.

viewtopic.php?f=3&t=26238&p=241614&hilit=excel#p241614
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Passing fixed-len string as arguments impossible?

Post by jj2007 »

Tourist Trap wrote:If we pass the zstring this way: BYREF AS ZSTRING, don't we loose the information on the size ?
Yes indeed. I tried a workaround, but it won't work because FB apparently does not use the process heap for allocating the string:

Code: Select all

#include "crt.bi"
#include "Windows.bi"

sub fillz(byRef zs as zstring)
  Dim sLen as Integer=HeapSize(GetProcessHeap(), 0, @zs)
  ? sLen	' returns zero...
  strcpy(zs, "Just a test")
end sub

dim as zstring*4 zstr
zstr = "abcdefg"

? zstr      'returns a, as expected

fillz(zstr)
? zstr      'returns abcdef!!!
Sleep
Boris the Old
Posts: 139
Joined: Feb 04, 2011 20:34
Location: Ontario, Canada

Re: Passing fixed-len string as arguments: possible but not recommended?

Post by Boris the Old »

Carlos Herrera wrote:
Boris the Old wrote: ... support for decimal arithmetic (floating point just isn't acceptable for business calculations)...
What's wrong with floating point in FB? Could you be more specific?
Carlos
The problem is not with FB's floating point features - it's a problem because decimal numbers (base 10) cannot be mapped exactly to binary numbers (base 2).

For example, if you assign $1.10 to a floating point variable, you will get something like 1.1000000238. And although this may not be a problem for a few simple calculations, it can create significant errors when accumulated over millions or billions of transactions.

But also consider the following piece of code, which is actually a worse problem:

Code: Select all

FloatValue = 1.10
FloatValue = FloatValue * 10    (now contains 11.000000238, but the expected decimal value is 11)
If FloatValue > 11 Then
  pay a large amount of income tax
Else
  pay no income tax
End If
As you can see, using floating point variables is not appropriate for doing decimal arithmetic. :-)

Rod
Post Reply