Silverfrost Forums

Welcome to our forums

UNDEF

8 Nov 2012 4:50 #10988

Hi there,

I have a routine that accesses binary-data in an array. I have Full checking code ticked.

One of my routines crashes with:

Error 112, Reference to undefined variable, array element or function result (/UNDEF)

Indeed my array does have UNDEFINED in them. However, I was told a while back to use 'cFTN95$INHIBIT_CHECK 11' in order to 'turn off' UNDEF for a file. Since I am using the '.f95' extension for my code I attempted to use '!FTN95$INHIBIT_CHECK 11' (as the first line of my source-file) but this appears not to work since I get the error as show above.

Please advise.

Marz

8 Nov 2012 8:58 #10989

You can disable checking options via a comment embedded directive but number 11 does not relate to /UNDEF.

Try

!FTN95$OPTIONS(-UNDEF)

and look at a /LIST or /EXPLIST to see if it has worked.

Better still, do not use /UNDEF on the command line (use /CHECK rather than /CHECKMATE).

Even better, are you sure that you need to switch this off. What will happen at runtime if values are not set?

8 Nov 2012 5:57 #10993

I do not recall the exact wording that was used when I was told to use 'cFTN95$INHIBIT_CHECK 11', but in the '.for' file it 'appeared' to have worked.

I have no idea what /LIST and /EXPLIST are, and have no idea how to look at them in order to see if it has worked.

I do not myself explicitly use '/UNDEF' on the command line, I am using the IDE to write and debug my code.

I do not know if I 'need' to switch /UNDEF off. If I knew how to read in a binary-file and access the data without having to do so then I would have already done so.

The values in the binary-file can be such that an UNDEFINED value is present when read into an array. So in the case for these particular routines I most certainly DO want an UNDEFINED value to 'happen'.

Regards

Marz

8 Nov 2012 7:39 #10995

When you install FTN95, the installation includes a file FTN95.CHM, which is a searchable Windows help file. In it is information on many things you will find helpful. One of the sections in this document describes compiler options. While it is easier to use compiler options in a command-line environment, you can invoke them when you are compiling through PLATO. The two listing options are described as follows:

/LIST [<filename>] more... Produces a source listing file. If <filename> is not provided, the name is created by replacing the source-suffix with .LIS, e.g. with FOO.F90, the map file would be FOO.LIS.

/EXPLIST [<filename>] Generate a listing file containing a symbolic assembler listing. <filename> is the optional name of the .LIS file. /EXPLIST is equivalent to /LIST but causes each source statement to be followed by the assembler statements corresponding to the instructions into which it was compiled.

If you generate a listing file you can look at it using any application that can read plain text files. If you don't understand assembly language, /EXPLIST isn't going to be very helpful.

There is nothing intrinsically wrong with having undefined values in any variable, but if you actually use those values in any conventional sort of arithmetic, you don't have a clue as to what the result will be, and the chance is that your program will produce nonesense. Many programs do this anyway, but it is difficult to believe that it is your intention!

The pattern of bits that signals a value is undefined in a floating point number may be perfectly valid if interpreted (say) as characters, or graphics, but then you need to access the relevant bytes in the right way.

Good luck!

Eddie

10 Nov 2012 10:11 #11014

Quoted from LitusSaxonicum

There is nothing intrinsically wrong with having undefined values in any variable, but if you actually use those values in any conventional sort of arithmetic, you don't have a clue as to what the result will be snip

The result will be undefined but you might not realise it 😃

I try to define only the variables I need in a particular scope and leave all the other variables that are in scope undefined. This way, if I make a mistake and reference one of the undefined varables in an expression, the run-time checking (/CHECKMATE) will show me my error.

For debugging, I also put a call in the program to explicitly undefine variables that should not be referenced, e.g.

call set_undefined(a)
call set_undefined(b)

where set_undefined is simply

subroutine set_undefined(var)
real, intent(out) :: var !< make var undefined using /CHECKMATE
end subroutine set_undefined

I actually have a collection of set_undefined in a module with one generic INTERFACE to handle all variable types and kinds.

In the following loop, a and tmp do not need to be carried from one loop iteration to the next, so are made undefined.

s = 0.0
do i=1, 100

    ! lose values when loop is entered and at last iteration
    ! comment out in production code.
   call set_undefine(a) 
   call set_undefine(tmp)



   ! Inadvertant reference of a or tmp here will give an error




   a = real(i)
   tmp = a**2  ! An error would occur here if i forgot to define a
   s = s + tmp ! An error would occur here if i forgot to define tmp

end do

This is extra work, but it helps to document the code and saves time during debugging.

10 Nov 2012 12:32 #11015

David,

Some useful ideas here, and food for thought, but probably too sophisticated for the needs of the original poster. I am certainly going to think about these approaches.

The business of the scope of a variable is far more complex when using modules in Fortran 90 et seq than it was in Fortran 77 and earlier, although even the latter could get you in trouble. (The facilities provided in the newer standards are solutions to problems that I don't have, and some of them produce problems that I never had before!)

Eddie

13 Nov 2012 11:32 #11037

The post was not 'too sophisticated' for me, I understand it well. I am however unsure if anyone has understood my problem 'sufficiently'.

I have binary data that I read into an Integer*1 array. Each element of this array is not necessarily a single entity with respect to the function that is accessing it. Many elements may be required to form a number that it requires.

For example, the function may need to extract:

array(73) at bit-positions 3 to 7 and array(74) at bit-positions 0 to 5

in order to retrieve an 11-bit number.

The problem is that each element of the array may have a bit-pattern that implies 'undefined', so when the function reads the data into an Integer*1 the error as stated in the original post occurs.

Marz

14 Nov 2012 1:46 #11038

For the code that requires this range of values, don't use compiler options that select /UNDEF. Once you are confident this code works correctly, why do you continue with /CHECK. I'd recommend using only /DEBUG.

John

14 Nov 2012 10:49 #11050

You have to store and define 8 bits at a time in your integer*1 array. You can store 6 bits for example with 2 leading bits set to 0.

You should be able to use TRANSFER to avoid the interpretation of a bit pattern as an undefined value.

What form is the binary data in?

Can we see a line or two of code which gives the error?

14 Nov 2012 7:58 #11056

'Too sophisticated' wasn't intended to be insulting. But your remark:

I have no idea what /LIST and /EXPLIST are, and have no idea how to look at them in order to see if it has worked.

does rather suggest that your requirements were basic, and I apologise if this was a misunderstanding.

If your array variable is integer, then you shouldn't ever get 'undefined' - because all possible bit patterns in an integer1 (one byte) are valid values (00000000 to 11111111 and everything in between represent the integers from -128 to +127). Whether you set bits yourself, or they are just random 'junk', the combination of bits in an integer1 is always a valid combination. Hence I don't understand why any part of FTN95 would throw a fit when presented with any values in integer1 format. Equally, character(1) is always valid, and represents characters for 0 to 255 in whatever character set you want.

You should only get a runtime error of undefined if you access a combination of bytes as real*something (4, 8 or 10 bytes), so my next guess is that you aren't always referring to the elements in that array as integer.

Your latest explanation refers to 11 bits extracted from 2 consecutive bytes, so my alternate guess is that Error 112 comes about if you are trying to squeeze that 11-bit combination back into an 8-bit space! In that case, the reference isn't to an undefined variable or array element when you access it, but to a function result.

However if you do not post any code, the true problem may never be found, as no-one here can do more than just guess at to the real nature of the problem. If you cannot extract the problem in just a few lines of code, it is possible to post a longer code in dropbox or its equivalent. There are clearly several people here who would like to help.

E

15 Nov 2012 5:53 #11060

@JohnCampbell:

When I am confident that some code works correctly I want to continue with /UNDEF because I will no doubt be writing more new code, which I am less confident about.

15 Nov 2012 6:06 #11061

@davidb

One defining and necessary condition of the program/data is that ALL 8-bits are used.

Here is the line (and associations) that causes trouble:

Header-file Start Type(Structure) . . . Integer*1, Pointer :: pstData(:) End Type(Structure) Header-file End

Subprogram Start !! Passed Type(Structure), INTENT(INOUT) :: pstTileDataP

!! Locals Integer4 :: iByteOffsetL Integer1 :: i1Value1L . . . i1Value1L = pstTileDataP%pstData(iByteOffsetL + 1) . . . Subprogram End

The value in the array at pstData(iByteOffsetL + 1) is: Z'80'_1 == 128

Marz

15 Nov 2012 6:08 #11062

Thanks to all who are trying to help with this 😄

15 Nov 2012 6:17 #11063

@LitusSaxonicum

I believe that my requirements are quite basic 😄

When I examine arrays that are of the Integer 1,2 and 4 bytes nature, I notice the following:

  1. 1-Byte: UNDEFINED pattern == Hex(80) == 128
  2. 2-Byte: UNDEFINED pattern == Hex(8080) == 32896
  3. 1-Byte: UNDEFINED pattern == Hex(80808080) == 2155905152

I Consequently struggle to know how to reply to your statement of:

'If your array variable is integer, then you shouldn't ever get 'undefined' - because all possible bit patterns in an integer1 (one byte) are valid values (00000000 to 11111111 and everything in between represent the integers from -128 to +127). Whether you set bits yourself, or they are just random 'junk', the combination of bits in an integer1 is always a valid combination.'

Regarding 'trying to squeeze that 11-bit combination back into an 8-bit space', the error occurs when I read the data from the Integer1 array into an Integer1 local variable, and therefore the functionality of the function does not matter at that point.

I thank you for your time and consideration on the matter 😄

Marz

15 Nov 2012 6:21 #11064

Further to this problem, I tried putting in the line:

!FTN95$OPTIONS(-UNDEF)

in order to switch off UNDEF for a module, and it 'worked'. It does however have an undesirable side-effect in that I can no longer debug through that module. Any attempt to F7 into it is ignored, and when I 'find' the routine (within the debugger) it returns a window with Assembly-Language therein.

When I remove the line shown abouve, then I am again able to debug the code, but of course the UNDEF problem occurs - lol

Is this 'normal' behaviour?

TIA

Marz

15 Nov 2012 6:59 #11065

I am not sure how far to go with you on this. At some point it would be advisable for you to read the manual.

However, having switched off /undef, you can switch on /debug to allow debugging.

15 Nov 2012 9:25 #11067

Can you try copying the value like this:

i1Value1L = transfer(pstTileDataP%pstData(iByteOffsetL + 1),  i1Value1L)

This copies the bits but won't be seen as an assignment so the undefined patten shouldn't be detected. 😉

Transfer is a standard intrinsic function. The second argument is used as a MASK to get the size in bits of the destination and doesn't need to be defined. It can be any integer1 variable or integer1 constant, including the destination variable. The first argument should be defined, which it is in your case, since -128 is a valid 1 byte integer.

For example, this code works for me with /UNDEF on or not.

program anon
integer*1 :: aaa
! aaa is not defined
call mmm(aaa)
end

subroutine mmm(ccc)
integer*1 :: ccc, bbb
bbb = transfer(ccc, bbb)
print *, bbb  ! should print -128 when /UNDEF on and a junk value when /UNDEF off
end

Incidentally, I am finding that /UNDEF only seems to detect 1 byte undefined integers when compiling for .NET. No errors are detected when I compile for Win32.

PS. Transfer has many cool uses, like getting the size of a data type in bytes, size(transfer(data_type, (/'A'/))), and also you can use it as a VOID pointer, ala C, C++ to do generic programming.

16 Nov 2012 5:11 #11068

For this and the previous topic, I would recommend that you review the compiler options you are selecting. I compile my program, using a batch file, selecting different levels of checking for different routines(files) as an FTN95 argument. The only compiler option I put in my code is WINAPP. I set all debugging compiler options in the batch files.

You can do a lot of checking, without resorting to /undef, such as /check.

If you are going to release an application you should also be aware of the amount of information included in the .exe if you use /check. You might not want to release all this information.

/debug is a very useful level of compile checking, as it is sufficient for maping the code in SDBG and providing an easily readable callback list, without the overhead of address checking or other tests. If the user finds a problem while the program is runing, they can give an informative report of where it occurs. If the problem occurs in the OS, outside the fortran code, then no checking options in the fortran code are likely to help identify that error source.

If you want to solve the problem, there are alternative approaches to the one you have been using.

John

18 Nov 2012 5:42 (Edited: 20 Nov 2012 1:09) #11082

I never include winapp. It scares people. LOL I use /win at compile time What it is for? Isn't it included automatically by the compiler because all works fine without it?

19 Nov 2012 2:57 #11089

@DanRRight, @JohnCampbell and @davidb and @others.

Thank you all for your wonderful feedback, I'm going to have a good think about my Development 'Style' and perhaps incorporate some of these ideas.

Thanks again.

Marz

Please login to reply.