如何通过iso_c_binding从Fortran调用C函数直接获取字符串?
iso_c_binding? Yes, there are cleaner, more straightforward approaches to get a C string into Fortran using iso_c_binding—you don’t strictly need the transfer function, or you can simplify how you use it. Let’s walk through two improved methods based on your existing code:
1. Simplify buffer-based transfer (your original workflow)
Since your C function writes a null-terminated string to a buffer provided by Fortran, you can either:
- Use the length value returned by C directly to slice the
c_chararray (no extra steps needed beyond what you’re already doing, but we can make it clearer) - Locate the null terminator (
c_null_char) in the array for safer conversion (in case the returned length ever has issues)
Here’s a revised Fortran subroutine that cleans up the conversion step:
subroutine strfromc(stringa) use iso_c_binding implicit none character(200) :: stringa interface subroutine getstrfromc(ld,d) bind(c,name='getString') import :: c_int, c_ptr integer(c_int) :: ld type(c_ptr), value :: d end subroutine getstrfromc end interface character(c_char), dimension(200), target :: d1 integer(c_int) :: ld1 integer :: null_pos call getstrfromc(ld1, c_loc(d1)) ! Option 1: Use the length returned by C (simple, matches your original logic) stringa = transfer(d1(1:ld1), stringa) ! Option 2: Use the null terminator for safer conversion (fallback if length is wrong) ! null_pos = index(d1, c_null_char) ! if (null_pos > 0) then ! stringa = transfer(d1(1:null_pos-1), stringa) ! else ! stringa = transfer(d1, stringa) ! end if write (6,*) 'SF stringa: "', trim(stringa),'"' return end subroutine
This removes unnecessary loops and keeps the conversion logic concise. The transfer function is still valid here, but we’re using it more intentionally instead of iterating through the array.
2. Let C return a string pointer (alternative workflow)
If you’re open to adjusting your C function, you can have it return a string pointer, then use Fortran’s c_f_pointer to map that pointer to a Fortran character array. This avoids preallocating a buffer in Fortran (though you still need to handle memory carefully).
Modified C function:
#include <stdio.h> #include <string.h> // Use a static buffer (no dynamic allocation, so no need to free in Fortran) char* getString() { static char buf[200]; printf("Enter a string:\n"); scanf("%[^\n]", buf); printf("C: w: %s\n", buf); return buf; }
Corresponding Fortran code:
program pr implicit none character(200) :: stringa call strfromc(stringa) write (6,*) 'FPR stringa: "', trim(stringa),'"' stop end program pr subroutine strfromc(stringa) use iso_c_binding implicit none character(200) :: stringa interface function getString() bind(c,name='getString') import :: c_ptr type(c_ptr) :: getString end function getString end interface type(c_ptr) :: c_str_ptr character(c_char), dimension(:), pointer :: f_char_arr integer :: null_pos ! Get the C string pointer and map it to a Fortran array c_str_ptr = getString() call c_f_pointer(c_str_ptr, f_char_arr, [200]) ! Max buffer size matches C's static buf ! Convert to Fortran string using the null terminator null_pos = index(f_char_arr, c_null_char) if (null_pos > 0) then stringa = transfer(f_char_arr(1:null_pos-1), stringa) else stringa = transfer(f_char_arr, stringa) end if write (6,*) 'SF stringa: "', trim(stringa),'"' return end subroutine
Note: If your C function uses dynamic allocation (malloc), you’ll need to add a corresponding C free function that Fortran can call via iso_c_binding to avoid memory leaks.
Key Takeaways
- For your original buffer-passing approach, simplifying the slice-and-transfer step is the most direct improvement.
- If you switch to a pointer-returning C function,
c_f_pointerlets you map the C string directly to a Fortran array without manual buffer management (as long as you handle memory correctly).
内容的提问来源于stack exchange,提问作者Francesco Uboldi

