- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For example
class foo
{
public:
int m_datalen;
double* m_pfoo_data;
foo(int datalen)
{
m_datalen = datalen;
m_pfoo_data = (double*)_mm_malloc(datalen*sizeof(double),16);
}
~foo()
{_mm_free(m_pfoo_data);
m_pfoo_data = 0;
m_datalen = 0
}
}
SoI want to be able to define a type foo in fortran that can be assigned to a subroutine dummy variable. I understand there is a way to do this using the a common block.
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is a 8 byte structure on 32-bit platform and 12 byte structure on 64-bit platform.
type foo
sequence
integer(4) :: datalen
integer(C_PTR) :: p_data
end type foo
Then you need to use something link thesubroutine C_F_POINTER
CALL C_F_POINTER(cptr, fptr [,shape])
Jim Dempsey
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Have you tried to simply call the Fortran routine by passing the address of the foo object and defining on the Fortran side a derived type containing the public data like:
[fortran]subroutine called_from cpp(dummy_arg) implicit none type foo sequence integer(4) datalen real(8) m_p_foo(datalen) end type type (foo) dummy_arg ../.. [/fortran]I am not sure that the sequence statement is mantadory but i guess that yes.
I am doing this frequently not from C++ but from Delphi.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, if you really want to force a double precision array to an odd alignment, you will require sequence.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is a 8 byte structure on 32-bit platform and 12 byte structure on 64-bit platform.
type foo
sequence
integer(4) :: datalen
integer(C_PTR) :: p_data
end type foo
Then you need to use something link thesubroutine C_F_POINTER
CALL C_F_POINTER(cptr, fptr [,shape])
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The issue you referenced relating to sequence related to pack or not with regard to fields within a record.
SEQUENCE will perform two functions:
1) sequence the fields in the order written in the source code
2) pack the fields together.
When the C/C++ record does not use packing, then you may have a problem as expressed in the other thread.
C/C++ orders the fields as written in source code but may pad fields to natural alignments. So you may have interoperability issues between FORTRAN and C/C++ when the struct layouts are not rigidly controlled on both sides.
Without SEQUENCE, the FORTRAN compiler is free to reorganize the order of the variables such to attain the natural alignments with fewer pads.
The safest way, would likely be a combination of SEQUENCE and UNIONs, and additionaly have a conditional compiled option (for both languages) to produce the offsets to the fields on each for use in an ASSERT.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Without SEQUENCE, the FORTRAN compiler is free to reorganize the order of the variables such to attain the natural alignments with fewer pads.
That is correct, but no Fortran compiler in the existing universe actually does that. There are compilers where sequence affects padding though.
The safest way is actually to use BIND(C) on the structure, which also prevents the reordering, should the Intel folks change their mind one day.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On the C/C++ side always use a packing of 1. This forces you to be cognisant of natural alignment issues within the struct if you want to address alignment for performance. As Jugoslav suggests, placing the larger member variables first generally is recommended. However, this does not resolve all issues. The totalstruct size is also an issue when you have an array of these structs. The conditional compiled option for ASSERT checking member variable offsets within the struct can also be extended to check for natural alignment. Then the asserts can now inform you of missing (required) pads.
[cpp]// padd.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "stddef.h" #include#pragma pack( push ) #pragma pack( 1 ) __declspec (align(64) ) struct foo_t { __int32 n; double d; }; #pragma pack( pop ) #define TEST_align(s,m) if(offsetof(s,m)%(sizeof((((foo_t*)0)->m)))) std::cout << "pad " #s " " #m " " << (offsetof(s,m)%(sizeof((s*)0)->m)) << std::endl; #if defined(TEST_align) void aligns_tests() { TEST_align(foo_t, n); TEST_align(foo_t, d); } #endif int _tmain(int argc, _TCHAR* argv[]) { foo_t foo; #if defined(TEST_align) aligns_tests(); #endif return 0; } [/cpp]
On x32 platform you will see:
pad foo_t d 4
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The most practical solution for the above example turns out to be
[bash]MODULE input_data USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE TYPE, BIND(C) :: CData INTEGER(C_INT) :: m_datalen TYPE(C_PTR) :: m_foo_data END TYPE CData REAL(8), DIMENSION(:), POINTER :: f_foo_data END MODULE input_data SUBROUTINE FOO_PROCESS(dataRec) USE input_data IMPLICIT NONE TYPE(CData), INTENT(INOUT) :: dataRec CALL C_F_POINTER(dataRec%m_foo_data, f_foo_data, [dataRec%m_datalen]) RETURN END SUBROUTINE FOO_PROCESS[/bash]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You haven't shown the C/C++ side of the problem.
The C/C++ struct could be using pack(1) or pack(other), but most likely a pack set by something else preceeding your struct definition.
BIND(C) on the FORTRAN side will not effect your choice of packing on the C/C++ side.
If BIND(C) implies SEQUENCE (with its implicit PACK=1), then the C/C++ side requires explicit packing of 1.
If BIND(C) implies natural alignment with member variables in order specified, then the C/C++ side must also use an alignment attribute such to produce natural aligned membervariables. One cannot assume anything about a default alignment.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Anyway, if you are going to worry about pragma's and command line switches changing alignment from whatever the C processor used by default then you need to worry that same variation on the fortran side too - because that could be changed just as easily.
For my edification: I always thought (possibly erroneously) that byte packing in common (and hence in sequence types) was an implementation detail in the general sense (beyond the requirements for two default reals in a double precision or complex, sizeof logical = integer = real on the second sunday of the month, etc). So if you had a type:
type silly
sequence
character(3) :: a
real :: b
end type silly
then there could be zero bytes, one byte, or four hundred and three bytes of "padding" in between %a and %b, it just needs to be the same everywhere that sequence of types appears in a storage association context. Or am I deluded?
Not that I use common, and hence not that I use sequence...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
sequence
character(3) :: a
real :: b
end type silly
I believe the above would be called a "character sequence type" and b would start at the 4th byte of the type.
Equivilent to:
#pragma pack(1)
struct
{
char a[3];
float b;
};
Note, the FORTRAN programmer should refrain from using "REAL" as this leaves an ambiguity as to the format. Use REAL(4) or better REAL(C_FLOAT).
use, intrinsic :: ISO_C_BINDING
...
type, bind(C) ::silly
sequence
character(3) :: a
real(C_FLOAT) :: b
end type silly
----------------
#pragma pack(push)
#pragma pack(1)
struct silly
{
char a[3];
float b;
};
#pragma pack(pop)
============= or ===========
use, intrinsic :: ISO_C_BINDING
...
type, bind(C) ::notsilly
character(3) :: a
real(C_FLOAT) :: b
end type notsilly
----------------
#pragma pack(push)
#pragma pack(8)
struct notsilly
{
char a[3];
float b;
};
#pragma pack(pop)
****
MS uses default packing of 8 meaning the alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.
The programmer should not assume anything about the packing. Any of the 100's, 1000'sof include files could alter the packing from that observed by a "Hello World" example probram.
Now as to if FORTRAN uses the packing of 8 or not with BIND(C) I cannot say. Steve might be able to answer this.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The "gotcha" I am stressing is if you include any header files, and/or use any command line options affecting packing you are never assured of getting default packing. It is very unusual that any C/C++ application calling FORTRAN support subroutines/functions would NOT contain #include "...".
Therefore, I urge you to explicitly specify the packing for the structs passed to FORTRAN. Your source code is not in control of contents of include files nor of command line. So assume:
If you do not declare packing, expect problems (sooner or later).
Same thing with assumption of size of int, INTEGER, long,REAL, LOGICAL, bool, and what happens with unsigned, etc...
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
BIND(C) at least avoids half of the problem, though I'm not sure which half...
[fortran]PROGRAM but_my_stars_never_align USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR, C_FLOAT IMPLICIT NONE TYPE seq_type SEQUENCE CHARACTER(9) :: a REAL :: b END TYPE seq_type TYPE(seq_type) :: sqt TYPE, BIND(C) :: bindc_type CHARACTER(LEN=9,KIND=C_CHAR) :: a REAL(C_FLOAT) :: b END TYPE bindc_type TYPE(bindc_type) :: bct ! If your computer has more bits than mine, then make this Z16.16. CHARACTER(*), PARAMETER :: fmt = "(A,': ',99(Z8.8,:,','))" !**** PRINT fmt, 'sequence: ', LOC(sqt), LOC(sqt%a), LOC(sqt%b) PRINT fmt, 'bind(c): ', LOC(bct), LOC(bct%a), LOC(bct%b) END PROGRAM but_my_stars_never_align [/fortran]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
On the C/C++ side always use a packing of 1. This forces you to be cognisant of natural alignment issues within the struct if you want to address alignment for performance.
I understand where you're coming from Jim, but if I may use a Buddhist metaphor, that approach reminds me of wearing a pebble in your shoe in order to be cognisant that suffering exists in this world. I prefer using the tools designed to do the job, and letting the compiler do its part of the job, not worrying about every gory implementation detail.
In a similar mindset, I don't expect that a randomly included, badly written header/include file affects alignment in my code. Should that happen, I would have a word with the author of that code (or ditch it through the window if it's 3rd party). But we can't -- and should not -- protect ourselves against every possible error or blunder in the tools of our environment (3rd party compilers, libraries, header files, hardware, you name it).

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page