April 27, 2024, 05:40:54 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


UDT

Started by GJ, December 27, 2006, 11:26:36 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

GJ

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


Ionic Wind Support Team

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"

Ionic Wind Support Team

GJ

Thanks Paul, working great !!

(wonder why it ever worked in IB standard..)  ;D


GJ

REDEBOLT

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?
Regards,
Bob

Ionic Wind Support Team

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 istring

An ISTRING requires a dimension, if ommited the length of the string is 0.  Change it to:

def a as STRING


Not 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$ <> ""


Ionic Wind Support Team

REDEBOLT

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?
Regards,
Bob

Ionic Wind Support Team

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.

Ionic Wind Support Team

REDEBOLT

Thanks, Paul, for the info.
Regards,
Bob

Rod

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!

Ionic Wind Support Team

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.
Ionic Wind Support Team