- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi there,
I read some numbers, as input to my code, from a text file. I want to set them as Parameter type to make sure their value is not being changed. Would that be possible?
Thanks!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, you can not do that as a parameter in the Fortran sense of the word, as that is a compile-time concept.
Fortran also doesn't have a concept of read-only variables, in the sense of setting the value once and then they are immutable, but what you can do is something along these lines:
module readonly_values implicit none type readonly private real :: value end type readonly contains subroutine set_value( var, value ) type(readonly) :: var var%value end subroutine set_value real function get_value( var ) type(readonly), intent(in) :: var get_value = var%value end function get_value end module readonly_values
If you then add suitable overloaded operators and assignments, such variables behave as if they are ordinary variables, with the exception that their value can only be set via the set_value routine.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Also if you read the data in a main program you could pass the data to a sub-program to do all the work and have the data items as intent(in) arguments. Thus any attempt to modify in the sub-program would be a compile time error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You may also want to look into "PROTECTED" attribute that is part of the Fortran standard: see here https://software.intel.com/en-us/node/526549.
Your data - the numbers you read in - can be made variables in a some "data" module and given the PROTECTED attribute; a procedure in this "data'' module can read them in from the file(s). You can then make other procedures that need these values to be outside the scope of this "data" module i.e., "contained" in other modules. These other procedures can access the numbers via USE statements on the "data" module. Owing to the PROTECTED attribute, these calling procedures will not be able to change the numbers and any attempt to do so can be caught by the compiler.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So ifort has PROTECTED now? Let's give it a test drive:
module M implicit none integer, PROTECTED :: i contains subroutine SET_I(J) integer J I = J end subroutine SET_I end module M program P use M implicit none call SET_I(10) write(*,*) I call S(I) write(*,*) I end program P subroutine S(I) implicit none integer I I = 20 end subroutine S
Output is:
10 20
So the protection is only syntactic. If you want protection to the extent of crashing the program on an attempt to change your variables, I think the only thing that will work is VirtualAlloc.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We have had PROTECTED for quite a while. Indeed it is only syntactic and can be gotten around. In the case you cite, since S has no interface the compiler doesn't know what it is doing with the argument. You can think of PROTECTED as similar to INTENT.
C551 A nonpointer object that has the PROTECTED attribute and is accessed by use association shall not appear in a variable definition context (16.6.7) or as the data-target or proc-target in a pointer-assignment-stmt .
That's really all it is.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Couldn't resist an example with VirtualAlloc!
module M use ISO_C_BINDING implicit none private public set_string public string character(LEN=:,KIND=C_CHAR), pointer, protected :: string integer, parameter :: SIZE_T = C_SIZE_T integer, parameter :: DWORD = C_LONG integer, parameter :: BOOL = C_INT integer(DWORD), parameter :: & MEM_COMMIT = int(Z'00001000',DWORD), & MEM_RESERVE = int(Z'00002000',DWORD), & MEM_RESET = int(Z'00080000',DWORD), & MEM_RESET_UNDO = int(Z'1000000',DWORD), & MEM_LARGE_PAGES = int(Z'20000000',DWORD), & MEM_PHYSICAL = int(Z'00400000',DWORD), & MEM_TOP_DOWN = int(Z'00100000',DWORD), & MEM_WRITE_WATCH = int(Z'00200000',DWORD) integer(DWORD), parameter :: & PAGE_EXECUTE = int(Z'10',DWORD), & PAGE_EXECUTE_READ = int(Z'20',DWORD), & PAGE_EXECUTE_READWRITE = int(Z'40',DWORD), & PAGE_EXECUTE_WRITECOPY = int(Z'80',DWORD), & PAGE_NOACCESS = int(Z'01',DWORD), & PAGE_READONLY = int(Z'02',DWORD), & PAGE_READWRITE = int(Z'04',DWORD), & PAGE_WRITECOPY = int(Z'08',DWORD), & PAGE_GUARD = int(Z'100',DWORD), & PAGE_NOCACHE = int(Z'200',DWORD), & PAGE_WRITECOMBINE = int(Z'400',DWORD) interface function VirtualAlloc(lpAddress,dwSize,flAllocationType, & flProtect) bind(C,name='VirtualAlloc') import implicit none !DEC$ ATTRIBUTES STDCALL :: VirtualAlloc !GCC$ ATTRIBUTES STDCALL :: VirtualAlloc type(C_PTR) VirtualAlloc type(C_PTR), value :: lpAddress integer(SIZE_T), value :: dwSize integer(DWORD), value :: flAllocationType integer(DWORD), value :: flProtect end function VirtualAlloc end interface interface function VirtualProtect(lpAddress,dwSize,flNewProtect, & lpflOldProtect) bind(C,name='VirtualProtect') import implicit none !DEC$ ATTRIBUTES STDCALL :: VirtualProtect !GCC$ ATTRIBUTES STDCALL :: VirtualProtect integer(BOOL) VirtualProtect type(C_PTR), value :: lpAddress integer(SIZE_T), value :: dwSize integer(DWORD), value :: flNewProtect integer(DWORD), intent(out) :: lpflOldProtect end function VirtualProtect end interface contains subroutine set_string character(100) input integer(SIZE_T) size type(C_PTR) cptr integer(BOOL) r4 integer(DWORD) lpflOldProtect write(*,'(a)',advance='no') 'Enter your string:> ' read(*,'(a)',advance='no',EOR=10,size=size) input read(*,'()') write(*,'(a)') 'Error in set_string: input too long.' stop 10 continue cptr = VirtualAlloc(C_NULL_PTR,size, & IOR(MEM_COMMIT,MEM_RESERVE),PAGE_READWRITE) if(.NOT.C_ASSOCIATED(cptr)) then write(*,'(a)') 'Error in set_string: memory allocation failed.' stop end if BLOCK character(LEN=size,KIND=C_CHAR), pointer :: fptr call C_F_POINTER(cptr,fptr) string => fptr end BLOCK string = input r4 = VirtualProtect(cptr,size,PAGE_READONLY,lpflOldProtect) if(r4 == 0) then write(*,'(a)') 'Error in set_string: protection failed.' end if end subroutine set_string end module M program P use M implicit none call set_string call callback(string) contains subroutine callback(MyString) character(*) MyString ! Read only character(*), parameter :: string = 'Not the actual string!' write(*,'(a)') 'The input string was: '//MyString MyString = 'Garbage' ! Attempt to change MyString write(*,'(a)') 'The changed string was: '//MyString end subroutine callback end program P
I/O with ifort:
Enter your string:> This is my string. The input string was: This is my string. forrtl: severe (157): Program Exception - access violation Image PC Routine Line Source VA.exe 00007FF630852BF3 Unknown Unknown Unknown VA.exe 00007FF630802902 Unknown Unknown Unknown VA.exe 00007FF630801111 Unknown Unknown Unknown VA.exe 00007FF6308682BE Unknown Unknown Unknown VA.exe 00007FF6308523EB Unknown Unknown Unknown KERNEL32.DLL 00007FFCBBD416AD Unknown Unknown Unknown ntdll.dll 00007FFCBDC6EB64 Unknown Unknown Unknown
And as anticipated, we have created a program that would rather die than change its input data. Surprising to me that PROTECTED and PRIVATE are not mutually exclusive. I anticipated three states: PUBLIC, PRIVATE, and PROTECTED, but it looks like Fortran defines 4 state: PUBLIC and PROTECTED, PUBLIC only, PRIVATE and PROTECTED, and PRIVATE only. What good is PRIVATE and PROTECTED?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I guess the committee didn't think it worthwhile to add a prohibition on specifying both. As you suggest, if an entity is PRIVATE then PROTECTED adds no value. But it does no harm either.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
RO, thanks for the VirtualAlloc with read only. Using the PROTECTED would protect from the (virtually all) unintended modifications, the VirtualAlloc and setting page to write protected would catch most of the rest, such as calling an interop C function with reference to the protected variable.
Jim
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page