What is the practical difference in having
subroutine fillName(person)
type(PersonType), intent(inout) :: person
person%name = "Name"
end subroutine
or the following
subroutine fillName(person)
type(PersonType), pointer :: person
person%name = "Name"
end subroutine
pointer has specific argument requirements that the bare description does not have. Basically the dummy argument person must be associated with a pointer target. It could be through an allocation or simple pointer assignment (=>). An important thing to note is that any changes to the pointer association of the dummy argument person during the execution of the subroutine will be reflected in the actual argument passed. The bare description will pass the actual argument by reference, but not pointer association.
If I assume the keyword is practical,
then the practical difference in the example you give would be readability, since they both work but intent(inout) is more explicit.
The technical difference is that the pointer may be null or undetermined, whereas with intent(inout) the variable have to be allocated. A pointer can also be associated or nullified in the subroutine but a dummy argument with intent(inout) cannot.
If you don't specify neither pointer or intent(inout) and you pass a pointer in argument then it have to be associated.
Related
I have a question about what value is passed to the C++ member function to invoke. When I disassemble a C++ member function like
void myClass::memberFunction() const;
I suppose it passed one implicit parameter this as the first and only parameter, but in fact, there could be two or more parameters passed.
I disassembled libobjc.A.dylib (iOS14.8-arm64e) with hopper. this function class_rw::method() const has no parameters, so I consider it pass only this pointer as the only parameter, but it has another (x1) parameter passed.
Then actual code is opensource on apple
https://opensource.apple.com/source/objc4/objc4-818.2/runtime/objc-runtime-new.mm.auto.html
And the snapshot is like
It seems the compiler auto-generated additional variables for this member function.
My question is that:
This should only happen when we put the implementation in the class declaration right?
This seems non-portable for classes that hides its implementation in another cpp file.
Is there a name for such an implicit added variable? I mean when we develop a compiler for c++, what do we call for such optimization?
From the ARM64 procedure call standard:
Result Return
The manner in which a result is returned from a function is determined by the type of that result:
If the type, T, of the result of a function is such that void func(T arg) would require that arg be passed as a value in a register (or set of registers) according to the rules in Parameter Passing, then the result is returned in the same registers as would be used for such an argument.
Otherwise, the caller shall reserve a block of memory of sufficient size and alignment to hold the result. The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine (there is no requirement for the callee to preserve the value stored in x8).
So this seems to be an example of the second type -- the return type method_array_t is something that is more than 16 bytes, so the caller allocates space for it and passes a pointer to that space as an extra argument.
The following works:
void* p = reinterpret_cast<void*>(0x1000);
But looks 'incorrect/unsafe' eg. 0x1000 is an int and not even uintptr_t, I could fix this, but is there a better/safer method of casting ?
0x1000 is an int and not even uintptr_t, I could fix this, but is there a better/safer method of casting
0x1000 is int, and in reinterpret_cast<void*>(0x1000) the compiler emits a sign extension instruction (sign is 0 here) or a plain register load instruction with an immediate operand to make the value as wide as void*.
For many reasons the compiler cannot possibly know whether 0x1000 represents a valid address, so it has to comply and assume that it is a valid address.
Casting integers representing addresses to pointers with reinterpret_cast is currently the existing practice.
You can create a pointer from an integer with reinterpret_cast.
However a pointer that does not point to to an existing object (or 1 past the last element in an array with an object being considered the sole element in an imaginary array for this purpose, or is the null pointer) has an invalid pointer value. Dereferencing is UB and other operations with invalid pointer values are implementation specific so you need to make sure your compiler allows the operations you do with these pointers.
void* p = reinterpret_cast<void*>(0x1000); // invalid pointer,
// operations on it are implementation defined
§6.7.2 Compound types [basic.compound]
[...] Every value of pointer type is one of the following:
3.1 — a pointer to an object or function (the pointer is said to point to the object or function), or
3.2 — a pointer past the end of an object (8.5.6), or
3.3 — the null pointer value (7.11) for that type, or
3.4 — an invalid pointer value
§8.5.1.10 Reinterpret cast [expr.reinterpret.cast]
A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.
[...]
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of
sufficient size (if any such exists on the implementation) and back to
the same pointer type will have its original value; mappings between
pointers and integers are otherwise implementation-defined.
You are allowed to convert from integer to pointer, but if the resulting pointer value doesn't point to an existing object (or one past an object) the resulting pointer has an invalid value.
Now regarding what you can do with invalid pointers:
§6.6.4 Storage duration [basic.stc]
[...] Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined
behavior. Any other use of an invalid pointer value has
implementation-defined behavior 35
35) Some implementations might define that copying an invalid pointer
value causes a system-generated runtime fault.
This post was heavily edited because it was wrong in its first iterations. Warm thanks to the community for correcting and challenging me.
tl;dr : You probably just shouldn't do this.
The following ... looks 'incorrect/unsafe' ... is there a better/safer method of casting ?
As another answer pointed out, this is "incorrect" to the extent of having implementation-defined behavior. Also, you're using a magic number.
But the issue is not the casting, I believe. I really kind of doubt you need to initialize a void* variable with literal address. Why?
If there's some kind of typed value at that address, then don't use void *, but rather a typed pointer. Even if you later want to pass that pointer to memset() or memcpy() or even some callback function which takes void * - delay the type erasure.
Where do you get that number from? Surely you know magic numbers are bad, right? Well, at the very least use something like
constexpr const uintptr_t sound_card_memory_mapped_buffer_address { 0x1000 };
this takes care of one of your concerns (not uintptr_t), and is also clearer to read, even if you stay with a void *:
void* p = reinterpret_cast<void*>(sound_card_memory_mapped_buffer_address);
p is a poor choice of name for a variable. Rename it according to its use.
Do you really need to initialize p at all? :
If you're not using it at the moment, why even initialize it? Try just not declaring it until it's about to be used (if at all).
If you're about to use it, why even declare it? Try:
do_something_with(sound_card_memory_mapped_buffer_address);
and no p in sight.
Obviously I have more questions than answers for you, since you only provided us a one-liner.
First) if you know that the type being passed to a procedure is not going to be extended should you use type() instead of class()?
Is there a performance difference?
Next) In the case of type-bound procedures, should the passed object dummy argument always be declared with class() and not type()?
Finally, in the case of this passed object, should an intent attribute be explicitly assigned or assumed? intent(in) or intent(inout)?
I would use type dummy arguments if the type is not extensible. It is much simpler and can be faster to work with non-polymorphic types. Of course, unless you require the type bound procedure, because:
Yes, that is a requirement. Type bound procedures require the passed argument to be polymorphic (class).
You should not assume implicitly any intent. It is best to set the right intent explicitly. Both combinations can be meaningful in different procedures.
As title states I wish to know does Fortran intent(inout) pass a copy of the value, or a pointer/reference to RAM address? The reason I need to know this is I need to pass a (relatively) big data matrix. If it creates a local copy that would cause me problems. Thank you!
Fortran does not specify details of how function and subroutine arguments are passed, but it does require that if a procedure modifies an intent(out) or intent(inout) argument then the changes will be visible to the caller after the procedure returns. It is common for compilers to implement this requirement by passing arguments by reference, but that is not the only possibility -- copy in / copy out is the main alternative.
You can normally rely on the compiler to implement the fastest behavior it can be certain is correct, which is usually pass by reference. There are cases where that cannot work, however, such as passing a non-contiguous array section to an assumed-size dummy argument, and there are sometimes cases where copy-in / copy-out is faster (maybe on certain large multiprocessor systems with segmented memory architectures).
The bottom line is that although you pose a good question, there is no general answer. As is often the case, you are best off to make it work first, and then make it faster if needed. Keep the array-copying question in the back of your head, but don't worry too much about it until you are in a position to test.
I'm trying to figure out the best way to use FORTRAN subroutines to work with big arrays of data.
I have a code which works on big 3,4 or 5 dimensional arrays.
I'm working with many subroutines and was wondering what is the best way to call these arrays by reference yet keeping them safe from writing (except for the output array, obviously).
I have read in [this related intent() question]: What is the explicit difference between the fortran intents (in,out,inout)? that I should use intent(out) to call by reference all the output arrays, however if I do the same with input arrays, then I probably need a C-like CONST to make it write-protected.
So the bottom line is:
1. How should I declare the dummy variables in terms of INTENT() for input and output variables?
2. How do I make called-by-reference variables write-protected for the subroutine?
Actually, C++ like const reference is very similar to intent(in), but more important is the distinction between assumed shape, assumed size, explicit size array dummy arguments.
For explicit size and assumed size arrays the Fortran rules have several requirements, that (in combination with the possibility of an implicit interface) make it necessary to use classical pass-by reference using a pointer to the first element.
However, the compiler does not have to pass the pointer to the original array, it can pass a pointer to a temporary copy.
For more complex passing mechanisms, which require explicit interface, a descriptor is passed (or a pointer to a descriptor). Again, the descriptor can in fact be of a temporary copy of the array. But these advanced passing mechanisms, as the assumed shape arrays, allocatable and pointer array arguments, make it less likely to need the temporary.
The temporary is always created when the value attribute is used. A pointer (or descriptor) to the temporary is passed.
If you use any of the intents, it shouldn't change much where no temporary was necessary. It is just a promise and the passing mechanism doesn't change.
When the temporary was necessary, the compiler can avoid one of the copies to or from the temporary if you specified intent(in) or intent(out).