- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am working on converting an exe to a dll. I am passing strings from c# to the dll, and the strings that are coming from c# are specified as follows:
character(len=1), dimension(*), intent(in) :: fileName
I am also passing an integer that gives the length of each string. This seems to work as expected, and I can easily iterate through the characters in the string using the passed length.
As I see it, the character declaration says essentially this: "this is a deferred length character array where each character is 1 byte in length, and the array itself can be any length."
The problem is that some of the code that I am interfacing with was written by another programmer. Though I consider my Fortran skills perhaps intermediate to advanced, I am having trouble grasping how to handle this situation.
The character variable that I need to copy the string to is defined as a deferred type variable as follows:
CHARACTER(:), ALLOCATABLE :: string_data
So this declaration, as far as I can tell, says something completely different, and it says this is a single character where the character itself can be any number of bytes in length.
NOTE: The array is subsequently allocated to the length of the string that it is expected to hold.
If I try to do a simple copy from the string that is coming from c# such as
string_data = fileName(1:fileNameLength)
The compiler gives me an error that says that the shapes of the arrays do not match. This, to me anyway, seems to make sense if I am correct about the meanings of the declaration statements. However, if I set that string to a string constant such as
string_data = '1234567890xyz'
it compiles fine, and works as expected.
If I change
CHARACTER(:), ALLOCATABLE :: string_data
to something that would match like the following:
CHARACTER(len=1), ALLOCATABLE :: string_data(:)
Not only does it give me hundreds of errors when I compile, there is also a chance that this will break a number of different programs since the code where this is declared is used for several other projects. So, I would prefer, if possible, not to change that code.
The closest I have come to getting this to work is with the following code:
read(string_data, *) fileName(1:fileNameLength)
However, this only reads the first character from "fileName", and I have am having difficulty determining a format specifier that will correctly convert the data types between the two.
Anyone have any suggestions as to how to handle this?
Thanks in advance!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, well figured that out quicker than I expected.
string_data = transfer(fileName(1:fileNameLen), string_data)
Thanks.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, well figured that out quicker than I expected.
string_data = transfer(fileName(1:fileNameLen), string_data)
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You might also perform allocation on assignment, does ifort still require a command line switch for this to work?
string_data = transfer(filename,repeat('A',fileNameLen))
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Some terminology notes:
character(len=1), dimension(*), intent(in) :: fileName
The above declares an assumed size array of type character with length one. The array (number of elements) assumes the size of the corresponding actual argument, if required the value of that corresponding size must be communicated separately.
CHARACTER(:), ALLOCATABLE :: string_data
The above declares an allocatable scalar of type character with deferred length. The length is specified when the scalar is allocated.
One way of copying the data from an array of size some_value to a scalar of length some_value is to use assignment in a loop.
! Assumed size dummy array of type character with length one (the default). ! (slightly different form of declaration, with same meaning, just for example.) CHARACTER, INTENT(IN) :: fileName(*) ! The size of above array/length of resulting scalar specified elsewhere ! (perhaps it is another dummy) INTEGER :: some_value ! Allocatable scalar of type character with deferred length. CHARACTER(:), ALLOCATABLE :: string_data ! An integer index. INTEGER :: i ! Specify the length of the scalar. ALLOCATE(CHARACTER(some_value) :: string_data) ! Copy the characters using a boring do loop. DO i = 1, some_value string_data(i:i) = fileName(i) END DO ! Or, depending on your source preferences, copy using multiple assignment (obsolescent syntax in F2015) ! FORALL (INTEGER :: j = 1:some_value) string_data(j:j) = fileName(j)
In the (possible future) case where the kind of the character array might be different from the kind of the character scalar, the assignment will do the appropriate conversion, you won't get that with TRANSFER.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To Repeat Offender's question: Beginning with the 17.0 compiler (PSXE 2017 release) a compiler option ( /assume:realloc_lhs ) is *no* longer needed. In 17.0 the default changed to match the Fortran 2003 standard so that allocatable arrays are automatically (re)allocated on intrinsic assignment as needed. As noted in the 17.0 RNs, to revert to the older behavior, specify /assume:norealloc_lhs or the new /nostandard-realloc-lhs compiler option.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page