Where have I gone wrong

General FreeBASIC programming questions.
Post Reply
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Where have I gone wrong

Post by fxm »

counting_pine wrote:I've made a bug report at https://github.com/freebasic/fbc/issues/111 .
Normal behavior.
See the note I had already added to the ZSTRING page.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Where have I gone wrong

Post by counting_pine »

Sometimes I think we need a "known bugs" section on wiki pages, to distinguish between buggy and intended beheviour..
Typically quirks like that should best be considered as Undefined Behaviour, or at least, implementation-defined. Not written into the specification.
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Where have I gone wrong

Post by grindstone »

Just for your information: row is of the Type ZString*4 Ptr Ptr, that means a pointer to an array of ZString*4 pointers.

Code: Select all

Dim PasswordChange As Integer = *row
(without index) generates an "Implicit conversion" warning, while

Code: Select all

Dim PasswordChange As Integer = *row[4]
generates nothing. Maybe the compiler simply doesn't expect a dereferencing around three corners. <grin>
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Where have I gone wrong

Post by fxm »

See also the dkl post: viewtopic.php?p=186883#p186883.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Where have I gone wrong

Post by counting_pine »

Thanks for the thread link.
I see that dkl calls this a shortcut, but like many shortcuts, it's basically a case of the compiler silently guessing at what you mean.
That's helpful when there's only one intuitive meaning, but this thread shows that there are at least two potentially intuitive meanings.

This is the clearest way for it to work:
- dereferencing a zstring ptr gives a zstring, i.e. a "stringy" object
- indexing a stringy object gives a character
- assignments/comparisons that mix numbers and stringy objects should be disallowed

(I also say in my thread that indexing zstring ptrs should be disabled. In 99% of cases, what you actually want is to index a zstring (i.e. a character in a string) or a zstring ptr ptr (i.e. a zstring ptr in an indexed list of zstring ptrs).)

Things like this just serve to highlight how unexpectedly complicated zstrings are, and it's because essentially we've somehow managed to fit three types (ubyte, zstring, zstring ptr) into two C types (char, char *).

To prevent confusion and misinterpretations in code, it shouldn't be possible to use two levels of indirection to accomplish the same thing.
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Where have I gone wrong

Post by fxm »

I also gave my opinion in 2013 in this same thread (which goes in your direction) and I do not use these shortcuts / automatic conversions.
But I saw them in some user codes (probably coding mistakes, but corrected by the compiler).
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Where have I gone wrong

Post by MrSwiss »

@counting_pine,

remember my first post in this forum, where you and TJF (mainly) helped me,
to get a related problem sorted out: C-String-Array to FB?

Which was eventually solved by using a: ByVal As ZString Ptr Ptr (as one of a
Sub's parameters).
Internal use was along those lines:

get one string from array: (*ZString Ptr)[idx1]
or, to get at a single Char: ZString[idx1][idx2] (byref access)

This has worked ever since, through from ver. 0.24.0 to current (incl. 1.05.0).
(I've not yet tested the 1.06.0 versions, 32/64.)
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Where have I gone wrong

Post by counting_pine »

MrSwiss wrote:get one string from array: (*ZString Ptr)[idx1]
or, to get at a single Char: ZString[idx1][idx2] (byref access)

This has worked ever since, through from ver. 0.24.0 to current (incl. 1.05.0).
(I've not yet tested the 1.06.0 versions, 32/64.)
As is, those obviously don't compile. But given sensible types, you'd expect (*MyZStringPtr)[idx1] to index a zstring and return a character.
MyZString[idx1][idx2] would index a zstring and get a character, but then try and fail to index the character.

Thinking about the levels of indirection is painful. It's almost worth doing away with zstrings entirely, using Ubyte Ptrs, and having a simple 'zstr(ubyte ptr)' function that returns a string. But of course it would break a lot of code.
Gablea
Posts: 1104
Joined: Apr 06, 2010 0:05
Location: Northampton, United Kingdom
Contact:

Re: Where have I gone wrong

Post by Gablea »

What I could not understand is why when I used

Dim PasswordChange as integer = *row[4] it would put that as 48 but when I used Dim PasswordChange as integer = VAL(*row[4]) it return the correct value. (where did the 48 come from)
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Where have I gone wrong

Post by counting_pine »

Firstly, let me just resay that it's hard to parse '*row[4]', and so after spending a couple of minutes experimenting, I would strongly advise using '*(row[4])' for unambiguity.

Since 'row' is a zstring ptr ptr, 'row[4]' is a zstring ptr.

Ordinarily, dereferencing a zstring ptr will give a zstring, effectively a string.
But since it's being assigned to a numerical variable, effectively 'row[4]' is treated as a ubyte ptr, and dereferencing it gives a ubyte - the ASCII value of the first character in the string.
(Disclaimer: this might not be exactly what happens internally.)
Some would consider this a bug in FBC.

But the Valint function (or the floating-point equivalent, Val) only takes strings, so there 'row[4]' is treated as a zstring ptr, and dereferencing it gives a zstring, as you'd expect.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Where have I gone wrong

Post by MrSwiss »

counting_pine wrote:As is, those obviously don't compile.
Of course not ;-)
I've just dug up the 'real thing':

Code: Select all

'' this is part of a WIN-DLL (FBC 32, only)
Sub CCalculateEx ( _
    ByVal PInput    As Double Ptr, _
    ByVal POutput   As Double Ptr, _
    ByVal PUser     As Double Ptr, _
    ByVal PStrings  As ZString Ptr Ptr _
    ) Export

	If CInt(PInput[_MSB]) > 2 Then								' Integer compare (way faster than double)
		*PStrings[SO] = Single2String(CSng(PInput[_SNG]))		' implicit second param. val = 0
	Else														' result = MSB first
		*PStrings[SO] = Single2String(CSng(PInput[_SNG]), 5)	' anything but 0. user supplied (Integer range)
	EndIf														' result = LSB first

End Sub
'' Single2String() is: Private Function(ByVal As Single, ByVal As Byte = 0) As String  '' not exported by DLL
Remark:
Strings work both ways (read or write or *both), here it is used as Output only ... (just written).
*both -- read first, write (actually overwrite) later
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Where have I gone wrong

Post by jj2007 »

counting_pine wrote:Things like this just serve to highlight how unexpectedly complicated zstrings are
... in FreeBasic.
coderJeff
Site Admin
Posts: 4323
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Where have I gone wrong

Post by coderJeff »

If you are C purist then UBYTE PTR is the way to go...

Code: Select all

#include once "crt/string.bi"
#include once "crt/stdio.bi"

scope
	print "UBYTE PTR is a char *"
	dim s as ubyte ptr = callocate( 100 )
	strcpy( s, @"string")
	printf( !"  char * is a string '%s'\n", s )
	printf( !"  char * is a char   '%c'\n", *s )
	printf( !"  char * is a value  '%d'\n", *s )
	'' *s = ucase( *s) '' not-allowed with UBYTE PTR
	print "  s[0]   = "; s[0]     '' print a char value 	
	print "  s[1]   = "; s[1]     '' print a char value 	
	print "  *(s+1) = "; *(s+1)   '' print a char value
	deallocate( s )
end scope
And if you are an fbc purist then STRING is the way to go....

Code: Select all

scope
	print "STRING"
	dim s as string
	s = "string"
	print "  string is a string '"; s; "''"
	print "  string is a char   '"; chr(s[0]); "''"
	print "  string is a value  '"; cubyte(s[0]); "'"
	s = ucase(s)
	print "  s[0]   = "; s[0]     '' print a char value 	
	print "  s[1]   = "; s[1]     '' print a char value 	
	print "  *(s+1) = "; asc(mid(s,2,1)) '' print a char value 	
end scope
If you read what ZSTRING is advertising, you will notice that it is neither UBYTE PTR as in C or STRING as in fbc, but is usable with both C procedures expecting a "char *" and fbc procedures expecting a "string"

ZSTRING is the intermediary between C and fbc...

Code: Select all

scope
	print "ZSTRING PTR is a char *, sort of"
	dim s as zstring ptr = callocate( 100 )
	*s = "string"
	print "  zstring is a string '"; *s ; "'"	
	print "  zstring is a char   '"; mid(*s,1,1) ; "'"	
	print "  zstring is a value  '"; asc(s[0]) ; "'"
	*s = ucase( *s ) '' allowed with zstring in fbc
	print "  s[0]   = "; s[0]     '' print a string 	
	print "  s[1]   = "; s[1]     '' print a string 	
	print "  *(s+1) = "; *(s+1)   '' print a string
	deallocate( s )
end scope
So to the point in the last few posts of this topic...
- mysql_row is typed as 'zstring ptr ptr' which is a pointer to an array of zstring ptr's.
- so, given dim x as mysql_row
- typeof(x )is typeof(zstring ptr ptr); I think the *4 or *8 is misleading if using #print typeof(...) for this
- therefore in x[a], [a] is pointer indexing, and is string indexing

Where does that leave us for *x[n]? If x is zstring ptr ptr?

x is a numbery thing; array of pointers
x[a] is stringy thing; pointer to zstring
x[a] might be a numbery thing or a stringy thing depending on context
*x[a] is a numbery (char value) thing or a stringy thing (reference to a specific char) related to the x[a] stringy thing, depending on context

Clear as mud? ;)

Bottom line:
- C has 'char *' which could be a sequence of 8-bit characters or an array of 8-bit values, depending on how it is used
- fbc has 'UBYTE PTR' which could be a sequence of 8-bit characters or an array of 8-bit values, depending on how it is used
- fbc has 'ZSTRING PTR' which is a sequence of 8-bit characters that can be passed to C or fbc functions
- ZSTRING is like a 'char *' in C and also like a 'STRING' in fbc
Post Reply