How do you copy MATLAB strings to Fortran character variables?

1 view (last 30 days)
Hellow,I am trying to copy MATLAB strings stored in a matlab structure (example: input.value='title') and copy it to a fortran Character variable using MEX files. When I use this code:
character*32 title
mwpointer titleptr
count=1
n=32
nelem=1
titlePtr=mxGetFieldByNumber(prhs(1), 1, 1)
call mxCopyPtrToCharacter(mxGetData(titleptr),title,n)
It only assigns the first letter 't' to the variable title. Do anyone know how to copy all the characters in the field and assign it to the variable? Thank you so much in advance.

Accepted Answer

James Tursa
James Tursa on 22 May 2015
Edited: James Tursa on 22 May 2015
Although it is not at all obvious from reading the doc, the mxCopyPtrToCharacter routine is intended to work only with C-style null-terminated strings that come from mat directories, not MATLAB character strings. Uh ... what??? I thought we were talking about Fortran, not C!!! Yes, we are, and yes, you read that correctly. Although these are Fortran API routines, the input string data they point to are assumed to be built using lower level C-style null-terminated strings. These Fortran API functions are pretty much useful only for reading the mat directory stuff (pointer to an array of char pointers) into Fortran variables. They are useless for converting a MATLAB char string into a Fortran character string.
The only clue you have to this fact is by carefully examining the example code in the supplied matdemo2.F file and having some knowledge of the similar functions in the C API. The matgetdir(mp, temp) call gets a pointer to an array of C-style (char *) types assumed to be null-terminated. Then the mxCopyPtrToPtrArray(dir, adir, ndir) call copies these C-style null-terminated string pointers into a Fortran mwPointer array (but the underlying strings these addresses point to are still C-style null terminated strings). Then the mxCopyPtrToCharacter(adir(i), names(i), M) call finally copies the C-style null-terminated string data itself into the Fortran character string variable.
The reason your code is only copying one character is because MATLAB char strings are 2-bytes per character. For typical ASCII characters, one of those bytes is null (0). When you pass the address of this to a routine expecting a C-style null-terminated string as input (1-byte per char), the routine sees that 0 in the 2nd byte and thinks it is the end of the C-style null-terminated string after copying only the first byte. Not what you wanted or expected.
OK, a lot of verbiage above mainly for background and to give more detail to the usage of the Fortran API functions. This answers why your code doesn't work, but doesn't solve your problem.
To get a MATLAB char string variable copied into a Fortran character string variable, you need to write custom code to do it. There are no API functions available for this unfortunately. This can be accomplished by recognizing that MATLAB char data is 2-bytes per character. Using that knowledge, one can type-pun the address of the MATLAB char data into an integer*2 array, then use those integer*2 values as ASCII codes to convert them into single characters in Fortran. The good news for you is I have already done that. The routine is posted below.
CAVEAT: I wrote this quickly off the top of my head ... it has not been compiled or tested. If you find bugs let me know.
!-----------------------------------------------------------------
!
! Copies MATLAB character string to Fortran character string
!
! Input: mx --> Address of mxArray containing char string
!
! Outputs: s --> Fortran character string (blank padded at end)
!
! Programmer: James Tursa
!
!-----------------------------------------------------------------
!
subroutine mxArrayToCharacter( mx, s )
implicit none
! ARG
mwPointer mx
character*(*) s
! FUN
mwPointer, external :: mxGetData
integer*4, external :: mxIsChar
mwPointer, external :: mxGetNumberOfElements
! LOC
mwPointer pr
mwPointer n
!-----
!\
! Check for NULL input
!/
if( mx == 0 ) then
s = ' '
return
endif
!\
! Check for char string input
!/
if( mxIsChar(mx) == 0 ) then
s = ' '
return
endif
!\
! Get char data pointer and number of characters
!/
pr = mxGetData(mx)
n = mxGetNumberOfElements(mx)
!\
! Call utility routine to treat MATLAB char data as integer*2
!/
call mxCopyI2toCharacter( %VAL(pr), n, s )
end subroutine
!
!-----------------------------------------------------------------
!
subroutine mxCopyI2toCharacter( I2, n, s )
implicit none
!-ARG
mwPointer n
integer*2 I2(n)
character*(*) s
!-LOC
mwPointer i, m
!-----
!\
! Copy 1 character at a time, using the 2-byte MATLAB char value as
! an integer value containing the ASCII character code. If there are
! not enough characters to fill s, blank pad the end.
!/
m = len(s)
do i=1,min(m,n)
s(i:i) = achar(I2(i))
enddo
if( n < m ) then
s(n+1:) = ' '
endif
return
end subroutine
  3 Comments
James Tursa
James Tursa on 22 May 2015
Thanks. I caught the missing "then" on a re-read and corrected the post, but not before you grabbed it. Glad it works.
James Tursa
James Tursa on 23 May 2015
Edited: James Tursa on 23 May 2015
I should make one other caveat. There is a Fortran API function for doing this called mxGetString. Many years ago I tried using it and it didn't work for me so I wrote custom code similar to what you see above. I know more now than I did then, so I can't be sure at this point if the problem then was with me or with mxGetString. I don't have a Fortran compiler to test with presently, but you might give mxGetString a try (hopefully it won't put a char(0) into your result).

Sign in to comment.

More Answers (0)

Categories

Find more on Fortran with MATLAB in Help Center and File Exchange

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!