How to get the address of array pointer in Fortran? - pointers

I would like to get the address of an array pointer. The prototype codes are as following:
program main
implicit none
type foo
integer, allocatable :: i(:)
integer j
end type
type(foo) a
integer, pointer :: ai(:)
ai => a%i
print *, "The address of a is ", loc(a)
print *, "The address of a%i is", loc(ai) ! <--- I expect the same address as a.
end program main
My final target is to get the address of a with type(foo) through the address of array pointer ai, since i is the first part of type(foo).
Thanks in advance!
Li

Fortran doesn't guarantee that the first item of a user-defined the same address as that user-defined type. Maybe there is a header before the items. Maybe there is some padding. Maybe the compiler stores the items in a different order. Maybe different compilers do it differently. None of this is specified. So your expectation may not occur. There is little need in Fortran for addresses. What are you trying to do? If you are interfacing to C, the ISO_C_Binding provides C_LOC.
EDIT in response to the comment. If your goal is to simplifying the variable name by omitting the leading "a %", you can use a pointer to create an alternative variable that accesses the same storage. You don't have to try to get past the language with pointers. Example:
program main
implicit none
type foo
integer, pointer :: i(:)
integer j
end type
type(foo) a
integer, pointer :: ai(:)
allocate ( a%i (5) )
a%i = [ 2, 5, 1, 3, 9 ]
ai => a%i
write (*, '( "a%i=", 5(2X,I2) )' ) a%i
write (*, '( "ai=", 5(2X,I2) )' ) ai
end program main
Output is:
a%i= 2 5 1 3 9
ai= 2 5 1 3 9

You can't, not using standard Fortran anyway.
Note that your expectations are misplaced.
loc is an extension. What it does is processor specific, but typically it will give you an integer representation of the address of the data object that the argument represents. (The F2003 standard's C_LOC is roughly equivalent.). In this case, the data object is an allocatable array. In all processors that I am aware of the storage for that array is not in the storage for the object of derived type that hosts the allocatable component. The derived type object simply contains a descriptor that describes where the array is stored (and how big it is, etc), not storage for the array itself.

Related

Deepcopy of a Fortran Pointer

I want to keep a deepcopy of the resulting fortran pointers from c_f_pointer for check purpose and so on.
(EDIT 1: I used 'deepcopy' as 'making a duplicate which is independent from its original'.
a = (/1,2,3,4/)
a_deepcopy = a
a_deepcopy(2) = 1
In above example, the original a remains (/1,2,3,4/) while a_deepcopy is changed to (/1,1,3,4/). If it was not a deepcopy, changing a_deepcopy's element would also change it's original a's element. I used the word 'deep copy' just becuase I've seen this kind of naming in Python context.)
program test1
use ...
use iso_c_binding
implicit none
...
type(c_ptr) :: rows_start_c, rows_end_c, col_indx_c, values_c
integer,pointer :: rows_start_f(:), rows_end_f(:), col_indx_f(:)
real*8 ,pointer :: values_f(:)
...
(*) call c_f_pointer(rows_start_c, rows_start_f, [DIM_r])
call c_f_pointer(rows_end_c , rows_end_f , [DIM_c])
call c_f_pointer(col_indx_c , col_indx_f , [rows_end_f(DIM_r)-1])
call c_f_pointer(values_c , values_f , [rows_end_f(DIM_r)-1])
...
end program test1
I've googled fairly much to find examples for the deepcopy of fortran pointer to allocatable array, which is the subject that somebody would have questioned already, but couldn't find a proper one.
The following code to copy a pointer to allocatable compiles and works fine so that deepcopy of 'pointer P' is generated in 'allocatable A2' array, but from the answers on my previous questions, I get to know that I'd better be careful treating pointer and allocatable in some mixed way even though they seems to work fine.
program pointer3
implicit none
real*8,allocatable :: A2(:)
real*8,target :: A(4)
real*8,pointer :: P(:)
A = 3.1416d0
P => A
allocate ( A2(size(A,1)) )
A2 = P # Assign 'pointer' to 'allocatable'
print *, 'Initially'
write(*,'(a, 4f6.2)') 'A ', A
write(*,'(a, 4f6.2)') 'P ', P
write(*,'(a, 4f6.2)') 'A2', A2
P(2) = 1.d0
print *, 'After'
write(*,'(a, 4f6.2)') 'A ', A
write(*,'(a, 4f6.2)') 'P ', P
write(*,'(a, 4f6.2)') 'A2', A2
end program
Initially
A 3.14 3.14 3.14 3.14
P 3.14 3.14 3.14 3.14
A2 3.14 3.14 3.14 3.14
After
A 3.14 1.00 3.14 3.14
P 3.14 1.00 3.14 3.14
A2 3.14 3.14 3.14 3.14 # A2 didn't changed after pointer modification, so a deepcopy seems to be generated
So the questions goes,
Is the above code right practice of deepcopying a pointer into a allocatable array?
If I were with ordinary fortran pointer and its target, I would try to deepcopy it to allocatable arrays just assigning its target attribute into the allocatable like below (Even though I can't do this since I'm with c_f_pointer and the equivalent target is c_ptr, which is not a fortran array).
program pointer3
implicit none
real*8,allocatable :: A2(:)
real*8,target :: A(4)
real*8,pointer :: P(:)
A = 3.1416d0
P => A
!allocate ( A2(size(A,1)) ) # Commenting this line does not induce a compile error, as well as a runtime error.
A2 = A # Assign 'target' to allocatable
print *, 'Initially'
write(*,'(a, 4f6.2)') 'A ', A
write(*,'(a, 4f6.2)') 'P ', P
write(*,'(a, 4f6.2)') 'A2', A2
P(2) = 1.d0
print *, 'After'
write(*,'(a, 4f6.2)') 'A ', A
write(*,'(a, 4f6.2)') 'P ', P
write(*,'(a, 4f6.2)') 'A2', A2
end program
This works fine as the first try of assigning a pointer right into allocatable array, but this seems weird because apparently 'A', and 'A2' differs on their type: real*8, allocatable and real*8, target.
I think both of above two methods to make deepcopy of a fortran pointer are neither proper, nor safe ones. How can I make a deepcopy of pointer in a safe, and robust way?
Thank you for reading this question.
A word of warning at the beginning: Pointers can be useful, but they are also very dangerous, in the sense that it's very easy to create very obscure and hard-to-debug mistakes with them.
I can't remember all that many cases where I honestly thought: Yes, pointers here are a good idea (though there were some).
Let's start with talking about arrays: Normal arrays have to have their shape declared at compile time, something like this:
INTEGER :: A(10)
This causes the program to set aside an area in memory to store ten integer values.
But you don't always know when coding how large the arrays actually have to be. That's why Fortran introduced allocatable arrays. Instead of declaring their shape at the beginning, the code tells the compiler that it should be prepared that memory will be needed later.
INTEGER, ALLOCATABLE :: A(:)
This tells the compiler that it will need an integer array, but it doesn't know how big it is yet. Then, when the program is running and it has figured out how large an array it needs, you can use the ALLOCATE command to actually create the memory:
ALLOCATE(A(100))
Only after you have called the ALLOCATE on the array can you actually use it. (Actually, there are more reasons to use allocatable arrays, but I won't go into the details yet.)
Pointers are different. They don't store the values, they store a memory address where the value is located. So before you can actually interact with the values, you first need to do one of two things:
Point the pointer to a target, for example:
P => A
Allocate memory that the pointer points to:
ALLOCATE(P)
You can see that also uses the ALLOCATE command, but it is used slightly differently: When you allocate an allocatable array, you associate the memory that you are allocating directly with the array. When you allocate a pointer, you allocate memory, and then write that memory's address into the memory associated with the pointer.
So with that said, let's go through what you're doing:
A is a more-or-less normal array, except that with the keyword target you've told the compiler that it should be possible to have pointers point at this array.
You set all elements of this array to a value.
P is a pointer to an array. You point P at A, which means that these two now work on exactly the same memory. Change one and the other will change as well.
Then you allocate memory for A2. A2 acts as just any other array, it has nothing to do with A or P.
Because P and A refer to the same memory, these two lines have the same effect:
A2 = A
A2 = P
In both cases, the contents of the array A are copied over to the memory of A2. Then, changing any value in A (and it doesn't matter whether you use A or P to do so) will also appear as a change in P. But the values of A2 will not be changed: They are stored somewhere else.
Thinking with pointers is really hard. When I actually have to do this, I most often sketch the process on a piece of paper beforehand, just so that I keep track on where which pointer is pointing at what time.
In Fortran, more often than not you won't need pointers. And without pointers, every copy is what you would call a 'deepcopy'.

Associate part of pointer array in Fortran [duplicate]

I have a problem assigning a pointer to a structure, to a pointer to a structure.
I use gfortran 4.6.3, and the name of the file is test_pointer_struct.f08 so I am using the Fortran 2008 standard (as supported by gfortran 4.6.3).
Hera comes the code:
PROGRAM test_pointer_struct
type tSmall
integer :: a
double precision :: b
end type tSmall
type tBig
integer :: h
type(tSmall), pointer :: member_small
end type tBig
type(tBig) :: var_big
type(tSmall), pointer :: var_small(:)
! We get an array of pointers to the small structure
allocate(var_small(3))
! Also allocate the member_small strucutre (not an array)
allocate(var_big%member_small)
var_big%member_small%a = 1
var_big%member_small%b = 2.0
! Now we want an element of the var_samall array of pointers, to point to the member_small in member_big
var_small(1) => var_big%member_small ! <- I get a compilation error here
! And dissasociate the member_small (we still maintain access to memory space through var_small(1)
var_big%member_small => NULL()
END PROGRAM test_pointer_struct
When I complie this, I get the following error:
Error: Se esperaba una especificación de límites para 'var_small' en (1)
Which could be translated as
Error: Limit specification expected for 'var_small' at (1)
What does this error mean?. What am I doing wrong?
Thank you very much in advance.
Fortran doesn't really do arrays of pointers. Your declaration
type(tSmall), pointer :: var_small(:)
doesn't define var_small to be an array of pointers to things of type tsmall; rather it defines it to be a pointer to an array of things of type tsmall.
When I compile your code Intel Fortran gives the rather more helpful error message
The syntax of this data pointer assignment is incorrect: either 'bound
spec' or 'bound remapping' is expected in this context.
which takes us to R735 in the Fortran 2003 standard. The compiler tries to parse var_small(1) not, as you wish, as a reference to the first element in an array of pointers but to either a bounds-spec-list or a bounds-remapping-list. The expression does not have the right syntax for either and the parse fails.
So that deals with the question of what the error means. What do you do about it ? That depends on your intentions. The usual suggestion is to define a derived type, along these lines
type myptr
type(tsmall), pointer :: psmall
end type myptr
and then use an array of those
type(myptr), dimension(:), allocatable :: ptrarray
Personally I've never liked that approach and have never needed to use it (I write very simple programs). I expect that with Fortran 2003 there are better approaches too but without knowing your intentions I hesitate to offer advice.

Pointer to derived type that contains allocatable array

Generally speaking I want to rename allocatable variables in a derived type that are passed through subroutine arguments. Writing everything with 'derived%type_xx' is not so pleasant. Besides, I don't want to spend extra memory on copying the values of the derived type to a new variable which costs new allocated memory. Furthermore, I know allocatable arrays are preferred than pointers for many reasons. I try to define pointers to the allocatable variable, but failed. I tried this because I want to simplify my code, both to be readable and not to be too long. I wonder if there's a way of achieving the goal? Thanks.
Here's the demonstration code:
Module module_type
IMPLICIT NONE
TYPE type_1
REAL,ALLOCATABLE :: longname_1(:), longname_2(:)
END TYPE
END MODULE
!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
USE MODULE module_type
IMPLICIT NONE
TYPE(type_1) :: input
input%longname_1 = input%longname_1 + input%longname_2 ! Use one line to show what I mean
END SUBROUTINE
And here's what failed:
Module module_type
IMPLICIT NONE
TYPE type_1
REAL,ALLOCATABLE :: longname_1(:), longname_2(:)
END TYPE
END MODULE
!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
USE MODULE module_type
IMPLICIT NONE
TYPE(type_1),TARGET :: input
REAL,POINTER :: a => input%longname_1 &
& b => input%longname_2
a = a + b ! much better for reading
END SUBROUTINE
It seems like a small issue, but I'd like to read my code without too much pain in the future. So what's the best option? Thanks a lot.
You can use the ASSOCIATE construct to associate a simple name with a more complex designator or expression.
You could also use the subobjects of the derived type as actual arguments to a procedure that carried out the operation.
You pointer approach failed because you had a rank mismatch - you were attempting to associate scalar pointers with array targets. You may also have had problems if an explicit interface to your procedure was not available in the calling scope. An explicit interface is required for procedures with dummy arguments with the TARGET attribute.
Use of pointers for this sort of simple name aliasing may reduce the ability of the compiler to optimize the code. Something like ASSOCIATE should be preferred.
Update: After #IanH made his comment, I have gone back to check: I was completely and utterly wrong on why your code failed. As he pointed out in his answer, the main issue is that pointer and target have to have the same rank, so you'd have to declare a and b as:
real, pointer :: a(:), b(:)
Secondly, before you can actually point these pointers to the targets, the targets have to be allocated. Here's an example that works:
program allocatable_target
implicit none
type :: my_type
integer, allocatable :: my_array(:)
end type my_type
type(my_type), target :: dummy
integer, pointer :: a(:)
allocate(dummy%my_array(10))
a => dummy%my_array
a = 10
print *, dummy%my_array
end program allocatable_target
If you have a Fortran 2003 compatible compiler, you can use associate -- which is specifically meant for this kind of issue. Here's an example:
program associate_example
implicit none
type :: my_type
integer, allocatable :: long_name_1(:), long_name_2(:)
end type my_type
type(my_type) :: input
integer :: i
allocate(input%long_name_1(100), input%long_name_2(100))
associate (a=>input%long_name_1, b=>input%long_name_2)
a = (/ (i, i = 1, 100, 1) /)
b = (/ (2*i+4, i = 1, 100, 1) /)
a = a + b
end associate
print *, input%long_name_1
end program associate_example
Inside the associate block, you can use a and b as a shortform for the declared longer named variables.
But other than that, I suggest you get an editor with proper code completion, then long variable names are not that much of an issue any more. At the moment I'm trying out Atom and am quite happy with it. But I have used vim with the proper expansions for a long time.

Is this use of character string pointers safe?

While implementing a string utility function, I came across a couple of character pointer expressions that I think may be unsafe. I googled, searched on SO, read my Fortran 95 language guide (Gehrke 1996) as well as various excerpts on display in Google books. However, I could not find any sources discussing this particular usage.
Both ifort and gfortran compile the following program without warning:
PROGRAM test_pointer
IMPLICIT NONE
CHARACTER(LEN=100), TARGET :: string = "A string variable"
CHARACTER(LEN=0), TARGET :: empty = ""
CHARACTER(LEN=:), POINTER :: ptr
ptr => NULL()
IF(ptr == "") PRINT *, 'Nullified pointer is equal to ""'
ptr => string(-2:-3)
IF(ptr == "") PRINT *, 'ptr equals "", but the (empty) sub string was out of bounds.'
ptr => empty(1:0)
IF(ptr == "") PRINT *, 'ptr equals "", it was not possible to specify subarray within bonds'
END PROGRAM
The output of the program is:
Nullified pointer is equal to ""
ptr equals "", but the (empty) sub string was out of bounds.
ptr equals "", it was not possible to specify subarray within bonds
So apparently, the evaluations of the pointer make sense to the compiler and the outcome is what you would expect. Can somebody explain why the above code did not result in at least one segmentation fault? Does the standard really allow out-of-bounds substrings? What about the use of a nullified character pointer?
edit : After reading Vladimir F's answer, I realized that I forgot to activate runtime checking. The nullified pointer actually does trigger a run time error.
Why they do not result in a segfault? Dereferencing a nullified pointer is not conforming to the standard (in C terms it is undefined behaviour). The standard does not say what a non-conforming program should do. The standard only applies to programs which conform to it! Anything can happen for non-conforming programs!
I get this (sunf90):
****** FORTRAN RUN-TIME SYSTEM ******
Attempting to use an unassociated POINTER 'PTR'
Location: line 8 column 6 of 'charptr.f90'
Aborted
and with another compiler (ifort):
forrtl: severe (408): fort: (7): Attempt to use pointer PTR when it is not associated with a target
Image PC Routine Line Source
a.out 0000000000402EB8 Unknown Unknown Unknown
a.out 0000000000402DE6 Unknown Unknown Unknown
libc.so.6 00007FA0AE123A15 Unknown Unknown Unknown
a.out 0000000000402CD9 Unknown Unknown Unknown
For the other two accesses, you are not accessing anything, you are creating a substring of length 0, there is no need to access the character variable, the result is just an empty string.
Specifically, the Fortran standard (F2008:6.4.1.3) says this about creating a substring:
Both the starting point and the ending point shall be within the
range 1, 2, ..., n unless the starting point exceeds the ending
point, in which case the substring has length zero.
For this reason the first part is not standard conforming, but the other ones are.

LOC() for user defined types gives different results depending on the context

I'm trying to debug some code in which members of a user defined object mysteriously change addresses, and while doing that I realized user defined objects do that as well. Here's a small example of querying object address from function that created it and then from its member function:
module foo_module
type foo_type
contains
procedure :: foo
end type foo_type
contains
subroutine foo(this)
class(foo_type) :: this
print *, 'Inside foo this is', loc(this)
end subroutine foo
end module foo_module
program trial
use foo_module
type(foo_type) :: object
print *, 'Object address', loc(object)
call object%foo()
end program trial
A sample output I get is:
Object address 4452052800
Inside foo this is 140734643354880
Why am I getting two different addresses for the same object? Am I doing something wrong? Or is there something with LOC that comes into play I don't understand?
I'm using ifort under osx.
LOC is an extension. Its behaviour is as specified by the compiler vendor.
What the behaviour intended by the vendor here isn't clear, but the difference that you are seeing is that in the main program you get the integer equivalent of the memory address of the non-polymorphic object (what you probably expect), while in the subroutine you get the integer equivalent of the memory address of the polymorphic descriptor for the object (maybe what you want, maybe not).
Using TRANSFER(C_LOC(xxx), 0_C_INTPTR_T) is a more portable way of getting the integer representation of the address of an object (where the C_* things are from the ISO_C_BINDING intrinsic module). C_LOC requires that its argument have the TARGET attribute and be non-polymorphic (use SELECT TYPE).
I'd recommend asking on the relevant Intel Forum if you want further clarification on the intended behaviour of the LOC extension.
I reported the bug to the developers our internal issue ID is DPD200253159. I found that the C_LOC function from ISO_C_BINDING works. For example:
subroutine foo(this)
use, intrinsic :: iso_c_binding
class(foo_type) :: this
print *, 'Inside foo this is', transfer(c_loc(this),0_C_INTPTR_T)
end subroutine foo

Resources