Hi, seems i'm stuck in this, can't figure out why the first returned value is different...
Any help appriciated
GJ
$MAIN
Def Version$:String:Version$=""
' just for testing reading/writing UDT , no other purpose intended
' build CONSOLE, and examined in DEBUG mode
def zoeker:bfile
def framename:string
def teller:int
def filelen:int
TYPE PrijsInfo
DEF Allnr[3] :ISTRING
DEF Allcode$:CHAR
DEF AllOmschr[29] :ISTRING
DEF AllPrijs$ :FLOAT
ENDTYPE
DEF Prijs:PrijsInfo
filelen=LEN(Prijs)
debugprint "Filelength="+STR$(Filelen)
framename="c:\001"
IF(OPENFILE(Zoeker,FrameName,"W") = 0)
Prijs.Allnr="100"
Prijs.Allcode$="X"
Prijs.AllOmschr="ABCDEFGHIJKLMNOPQRSTUVWXYZ12"
'' Prijs.AllOmschr="12"
Prijs.AllPrijs$=3.45
PUT Zoeker,1,Prijs
CLOSEFILE Zoeker
ENDIF
IF(OPENFILE(Zoeker,FrameName,"R") = 0)
GET Zoeker,1,Prijs
debugprint "ARTIKELNR = "+Prijs.Allnr
debugprint "len artikelnr "+STR$(LEN(Prijs.Allnr))
debugprint "ARTIKELCODE = "+Prijs.Allcode$
debugprint "len code "+STR$(LEN(Prijs.Allcode$))
debugprint "ARTIKEL OMSCHR = "+Prijs.AllOmschr
debugprint "len artikelomschr "+STR$(LEN(Prijs.AllOmschr))
debugprint "PRIJS = "+STR$(Prijs.AllPrijs$)
debugprint "len prijs "+STR$(LEN(Prijs.AllPrijs$))
CLOSEFILE Zoeker
ENDIF
END
You have to account for terminating NULL's in strings.
DEF Allnr[3] :ISTRING
Gives you two characters plus the terminating NULL character.
Prijs.Allnr="100"
Thanks Paul, working great !!
(wonder why it ever worked in IB standard..) ;D
GJ
I'm experimenting with the above code and trying to figure how to determine the length of the UDT. I discovered that if I assign a string longer than what is defined, the excess overlays the following fields. The LEN function returns the actual length of the string instead of the DEF'ed string. Therefore, I must check for the length of the assignment string to be one less than the length of the DEF'ed string. How can I obtain the length of the DEF'ed string?
TYPE PrijsInfo
DEF Allnr[3] :ISTRING
DEF Allcode$:CHAR
DEF AllOmschr[29] :ISTRING
DEF AllPrijs$ :FLOAT
ENDTYPE
DEF Prijs:PrijsInfo
filelen=LEN(Prijs)
Prijs.Allnr = "ABCDEFGHI"
Prijs.Allcode$ = "6"
debugprint "Allnr......value="+Prijs.Allnr[0]
debugprint "Allnr......value="+Prijs.Allnr[1]
debugprint "Allnr......value="+Prijs.Allnr[2]
debugprint "Allnr......value="+Prijs.Allnr[3]
debugprint "Allnr......value="+Prijs.Allnr[4]
debugprint "Allnr......value="+Prijs.Allnr[5]
debugprint "Allnr......value="+Prijs.Allnr[6]
debugprint "Allnr......value="+Prijs.Allnr
debugprint "Allcode$...value="+Prijs.Allcode$
debugprint "AllOmschr..value="+Prijs.AllOmschr
debugprint "AllPrijs$..value="+str$(Prijs.AllPrijs$)
debugprint "Allnr.length="+STR$(len(Prijs.Allnr))
debugprint "Allnr.length="+STR$(baselen(Prijs.Allnr))
debugprint "File..length="+STR$(Filelen)
The only thing I can think of is to define a constant for the string length.
So I try this:
const deflenAllnr = 3
const deflenAllOmschr = 29
TYPE PrijsInfo
DEF Allnr[deflenAllnr] :ISTRING
DEF Allcode$:CHAR
DEF AllOmschr[deflenAllOmschr] :ISTRING
DEF AllPrijs$ :FLOAT
ENDTYPE
def a as istring
DEF Prijs:PrijsInfo
filelen=LEN(Prijs)
a = "ABCDEFGHI"
if len(a) < deflenAllnr then
Prijs.Allnr = a
else
Prijs.Allnr = left$(a,deflenAllnr-1)
endif
a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
debugprint "a="+a
debugprint "len(a)="+str$(len(a))
stop
if len(a) < deflenAllOmschr then
Prijs.AllOmschr = a [color=red]<---- Access Violation here![/color]
else
Prijs.AllOmschr = left$(a,deflenAllOmschr-1)
endif
Prijs.Allcode$ = "6"
debugprint "Allnr......value="+Prijs.Allnr[0]
debugprint "Allnr......value="+Prijs.Allnr[1]
debugprint "Allnr......value="+Prijs.Allnr[2]
debugprint "Allnr......value="+Prijs.Allnr[3]
debugprint "Allnr......value="+Prijs.Allnr[4]
debugprint "Allnr......value="+Prijs.Allnr[5]
debugprint "Allnr......value="+Prijs.Allnr[6]
debugprint "Allnr......value="+Prijs.Allnr
debugprint "Allcode$...value="+Prijs.Allcode$
debugprint "AllOmschr..value="+Prijs.AllOmschr
debugprint "AllPrijs$..value="+str$(Prijs.AllPrijs$)
debugprint "Allnr.length="+STR$(len(Prijs.Allnr))
debugprint "AllOmschr.length="+STR$(len(Prijs.AllOmschr))
debugprint "File..length="+STR$(Filelen)
Here is the result:
Starting debug session...
Loading DLL: ntdll.dll
Loading DLL: C:\WINDOWS\system32\kernel32.dll
Loading DLL: C:\WINDOWS\system32\GDI32.DLL
Loading DLL: C:\WINDOWS\system32\USER32.dll
Loading DLL: C:\WINDOWS\system32\CRTDLL.DLL
Loading DLL: C:\WINDOWS\system32\IMM32.DLL
Loading DLL: C:\WINDOWS\system32\ADVAPI32.dll
Loading DLL: C:\WINDOWS\system32\RPCRT4.dll
a=ABCDEFGHIJKLMNOPQRSTUVWXYZ
len(a)= 26
User breakpoint encountered: Address 0x004061BF
First chance exception: Address 0x0040722C Access Violation.
Final chance exception: Address 0x0040722C Access Violation.
What did I do wrong?
QuoteI'm experimenting with the above code and trying to figure how to determine the length of the UDT
That isn't what's represented in your code. The length of a UDT is easily determined. PRINT LEN(PrijsInfo)
You are making it too hard on yourself.
LEFT$ copies the entire string if the length of the string is shorter than the TO character. In otherwords if you use LEFT$(a, 100) and a is only 3 character long then the 3 characters get copied up to the NULL. So you don't need the IF statmentents at all.
And you are crashing because of THIS:
def a as istringAn ISTRING requires a dimension, if ommited the length of the string is 0. Change it to:
def a as STRINGNot to worry, common newbie mistake ;)
OPENCONSOLE
const deflenAllnr = 3
const deflenAllOmschr = 29
TYPE PrijsInfo
DEF Allnr[deflenAllnr] :ISTRING
DEF Allcode$:CHAR
DEF AllOmschr[deflenAllOmschr] :ISTRING
DEF AllPrijs$ :FLOAT
ENDTYPE
def a as string
DEF Prijs:PrijsInfo
filelen=LEN(Prijs)
a = "ABCDEFGHI"
Prijs.Allnr = left$(a,deflenAllnr-1)
a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Prijs.AllOmschr = left$(a,deflenAllOmschr-1)
Prijs.Allcode$ = "6"
print "Allnr......value="+Prijs.Allnr[0]
print "Allnr......value="+Prijs.Allnr[1]
print "Allnr......value="+Prijs.Allnr[2]
print "Allnr......value="+Prijs.Allnr
print "Allcode$...value="+Prijs.Allcode$
print "AllOmschr..value="+Prijs.AllOmschr
print "AllPrijs$..value="+str$(Prijs.AllPrijs$)
print "Allnr.length="+STR$(len(Prijs.Allnr))
print "AllOmschr.length="+STR$(len(Prijs.AllOmschr))
print "File..length="+STR$(Filelen)
DO:UNTIL INKEY$ <> ""
Thanks, Paul, for clearing up the STRING thing.
I was trying to calculate the length of the UDT by adding up the field lengths.
TYPE PrijsInfo
DEF Allnr[3] :ISTRING ====> 3
DEF Allcode$:CHAR =====> 1
DEF AllOmschr[29] :ISTRING ==>29
DEF AllPrijs$ :FLOAT ======> 4
ENDTYPE TOTAL =====> 37
Is there padding somewhere?
Yes all UDT's (structures) have a packing alignment value. You can specify what packing value you want with the optional parameter in the TYPE statement.
TYPE name, {packing}
Listed in the users guide, alphabetical function reference, TYPE.
The packing value tells the compiler how to align the members in memory. Default alignment is on word boundries, up to an elements size of 8 bytes. This is the same default that C compilers and the Windows API uses. Emergence follows ANSI specs for structure packing and alignment.
In order to align members in memory, on word boundries, the compiler will add NULL pad bytes. If you specify a packing value of 1, suitable for disk files, then no pad bytes will be added.
And the reason for padding members is the Intel (and compatible) processors reads data stored on word memory boundries faster than on an odd memory address. In fact in order to read an odd memory address and internal exception has to be generated in the CPU, which takes much longer than just moving the data.
Here is the wikipedia text on the subject:
http://en.wikipedia.org/wiki/Data_structure_alignment
Mainly gives C references but the principles are the same. In C, such as when you are converting header files, the #pragma pack(n) directive controls structure packing.
Paul.
Thanks, Paul, for the info.
Good info, Paul, on packing, and I think I understand most of it.
Can you help me understand why I would choose a specific packing value? Are different packing values best for different purposes?
Thanks!
Unless you have a specific reason to change it you should leave it at the default. There are exceptions of course:
If you are primarily using the UDT with a disk file you can save some bytes by using 1 byte packing, although that isn't much of an issue these days it was a real concern back when hard drives were only 5-20 MB.
Some Windows functions expect packing to be set to a certain value. All structures dealing with bitmaps (and icons) in memory are 2 byte packing. Which had to do with bitmaps and 16 bit windows. The bitmap structure used for reading images from a file is 1 byte packing.
The problem with packing has always been where to determine what the packing value is supposed to be for a specific Windows structure. MSDN doesn't usually mention the value in the reference for the structure. So the best place to determine the value to be used is look in the C header file that contains the definition.
Paul.