I have a fortran subroutine that I call from C# and want to be able to terminate. This I can do using an integer variable that I alter in C# as the fortran routine runs. However changing this to a bool / logical(c_bool) does not work. (In the code below is also an option where I change a value in a callback function.)

Working code (with int parameters) C#:

using System.Runtime.InteropServices;

Console.WriteLine("C# starting");
var cb = new Natives.ActionRefInt(OnUpdateProgress);
var terminate = 0;
var t = Task.Run(() => Natives.TestCallBackAndVariable(cb, ref terminate));
for (int i = 0; i < 4; i++)
{
    await Task.Delay(900);
    terminate = i * 100;
    Console.WriteLine($"C# loop i = {i}, terminate = {terminate}");
}
terminate = -1;
await t;


static void OnUpdateProgress(ref int val2)
{
    Console.WriteLine($"C# OnUpdateProgress received val2 = {val2}");
    val2 += 10;
    Console.WriteLine($"C# OnUpdateProgress setting val2 = {val2}");
}
public static class Natives
{

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void ActionRefInt(ref int progress);

    [DllImport(dllName: "FortranLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void TestCallBackAndVariable(
    [MarshalAs(UnmanagedType.FunctionPtr)] ActionRefInt callBack,
    ref int terminate);
}

Fortran:

subroutine TestCallBackAndVariable(callBack, terminate)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBackAndVariable
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBackAndVariable" :: TestCallBackAndVariable
use ISO_C_BINDING
implicit none
! Variables
external                        ::  callBack
integer(C_INT),intent(inout)   ::  terminate
integer(C_INT)                  ::  ii
integer(C_INT)                  ::  val2
! Body of TestCallBackAndVariable
write(*,*) "Starting TestCallBackAndVariable in fortran lib"
do ii = 1,10
    call sleep(1)
    val2 = ii
    call callBack(val2)
    write(*,*) "Fortran loop ii = ",ii,", and terminate = ", terminate, ", and val from callback = ", val2
    if (terminate<0) exit
end do
write(*,*) "Finished TestCallBackAndVariable in fortran lib"
end subroutine TestCallBackAndVariable

Not working as expected code (with bool / logical) C#:

using System.Runtime.InteropServices;

Console.WriteLine("C# starting");
var cb = new Natives.ActionRefBool(OnUpdateProgress);
var terminate = false;
var t = Task.Run(() => Natives.TestCallBackAndVariable(cb, ref terminate));
for (int i = 0; i < 4; i++)
{
    await Task.Delay(900);
   
    Console.WriteLine($"C# loop i = {i}, terminate = {terminate}");
}
terminate = true;
await t;


static void OnUpdateProgress(ref bool val2)
{
    Console.WriteLine($"C# OnUpdateProgress received val2 = {val2}");
    val2 = true;
    Console.WriteLine($"C# OnUpdateProgress setting val2 = {val2}");
}

public static class Natives
{

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void ActionRefBool(ref bool progress);

    [DllImport(dllName: "FortranLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void TestCallBackAndVariable(
    [MarshalAs(UnmanagedType.FunctionPtr)] ActionRefBool callBack,
    ref bool terminate);
}

Fortran:

subroutine TestCallBackAndVariable(callBack, terminate)
!DEC$ ATTRIBUTES DLLEXPORT::TestCallBackAndVariable
!DEC$ ATTRIBUTES DECORATE,ALIAS:"TestCallBackAndVariable" :: TestCallBackAndVariable
use ISO_C_BINDING
implicit none
! Variables
external                        ::  callBack
logical(C_BOOL),intent(inout)   ::  terminate
integer(C_INT)                  ::  ii
logical(C_BOOL)                 ::  val2
! Body of TestCallBackAndVariable
write(*,*) "Starting TestCallBackAndVariable in fortran lib"
do ii = 1,10
    call sleep(1)
    val2 = .false.
    call callBack(val2)
    write(*,*) "Fortran loop ii = ",ii,", and terminate = ", terminate, ", and val from callback = ", val2
    if (terminate) exit
end do

write(*,*) "Finished TestCallBackAndVariable in fortran lib"
end subroutine TestCallBackAndVariable
subroutine TestArray(i,j,arr)

In the bool/logical variant does not c# modify value of the logical terminate fortran variable. However, changing the logical value in the OnUpdateProgress does work. (propagates back to fortran)

Help on this is, as always, much appreciated.

(VS 2022 NET 6, IFORT 2021.6.0 64bit)

推荐答案

In Fortran, the logical(kind=c_bool) type maps to the C _Bool type of the companion C processor (=compiler).

In C, _Bool is defined to be an unsigned integer type (size is implementation dependent but typically one byte) however with only two allowable values, 0 for false and 1 for true (0 and 1 here meaning the unsigned integer bit patterns that represent the integer values 0 and 1). Any other bit pattern is a trap representation and invokes undefined behavior.

However, in C# the internal representation of Bool variables is, per the ECMA CLI spec ( What is the binary representation of a boolean value in c# ), 0 for false, and all other bit patterns (that is, with any of the bits set to 1) are true.

Thus, AFAICT, the Fortran logical(c_bool) and the C# bool type are NOT interoperable, and you need some other mechanism to transfer boolean values between Fortran and C#. E.g. transferring them as integers.

Csharp相关问答推荐

如何将字节数组转换为字符串并返回?

在一个模拟上设置一个方法,该模拟具有一个参数,该参数是一个numc函数表达式

使用C#中的SDK在Microsoft Graph API上使用SubscribedSkus的问题

在调整大小的控件上绘制

使用预定义对象减少Task.Run/Factory.StartNew中的关闭开销

在此系统上已禁用获取正在运行的脚本.&在ASP.NET Core Web API中

NET8 MAUI并部署到真实设备上进行测试

N层解决方案上的依赖注入-删除样板

依赖项注入、工厂方法和处置困境

如何使用用于VS代码的.NET Maui扩展在我的iOS/Android设备或模拟器上进行调试?

如何在特定环境中运行dotnet测试?

ASP.NET MVC数据批注验证组复选框

在同一个捕获中可以有多种类型的异常吗?

EF Core 7-忽略模型绑定中的虚拟属性

如何将默认区域性更改为fr-FR而不是en-US?

C#使用相同内存的多个数组

如何在ASP.NET Core 8中获取键控服务词典

如何消除Visual Studio错误,因为它不识别集合表达式的新C#12语法?

最小API定义的Swagger标头参数

如何处理ASP.NET Core中包含两个构造函数的控制器?