c++ 在“nullptr”上检查“c_associated”将导致segfault,除非指针具有“value”属性

r8uurelv  于 2023-03-14  发布在  其他
关注(0)|答案(1)|浏览(161)

简而言之:我有一个fortran子例程,它接受一个c_ptr,并使用c_associated检查它是否是null,除非我给予指针赋予VALUE属性,否则检查将触发segfault。
我已经找到了解决这个问题的方法,但是我对导致这种行为的原因很感兴趣。在我看来,这似乎与Fortran隐式地通过引用传递有关。对于我的主库(未显示),这种行为只有在我使用优化编译时才会出现(使用-O0 -g时不会),但是我无法创建一个最小的示例来重现这种行为。
示例:
在main.cpp中

#include <iostream>

extern "C" {
void test_ptr(double* ptr);
}

int main(){
  
  double* ptr{nullptr};

  std::cout << "In C++, pointer is " << ptr << std::endl;
  test_ptr(ptr);
  std::cout << "Fortran exited without fault." << std::endl;

  return 0;
}

test.f90

module test
use, intrinsic :: iso_c_binding
public test_ptr

contains

subroutine test_ptr(ptr) BIND(C)
    use, intrinsic :: iso_c_binding
    type(c_ptr), target, intent(in) :: ptr

    print*, "In Fortran, pointer is", ptr

    if (c_associated(ptr)) then
        print*, 'Pointer is not null'
    else
        print*, 'Pointer is null'
    endif

end subroutine test_ptr

end module test

如果我编译并将其与

gfortran -c test.f90 test.o -O3
g++ -c main.cpp main.o -O3
g++ -o main main.o test.o -lgfortran

运行./main得到

In C++, pointer is 0
 In Fortran, pointer is                    0
Segmentation fault: 11

我发现了两种解决方法:

  • 或者 * 通过将ptr声明为
type(c_ptr), target, intent(in), value :: ptr
  • 或 *,方法是将C++端更改为传递&ptr,as。
extern "C" {
void test_ptr(double** ptr);
}

int main(){
  
  double* ptr = nullptr;

  std::cout << "In C++, pointer is " << ptr << std::endl;
  test_ptr(&ptr);
  std::cout << "Fortran exited without fault." << std::endl;

  return 0;
}

这两项更改(单独)都将产生预期输出

In C++, pointer is 0
 In Fortran, pointer is                    0
 Pointer is null
Fortran exited without fault.

在我看来,c_associated似乎在某个时候试图解引用ptr,而没有首先检查它是否是null,这是预期的行为吗?有没有其他(首选)方法来检查c_ptr是否是null

bkhjykvo

bkhjykvo1#

value属性是Fortran 2003的一项功能(一些编译器在此之前支持它作为扩展)。没有它,它假定指针ptr是 * 按地址传递 *(在C中),尽管由intent(in)定义了恒定性,这相当于引用C++中的指针。而且您提供了一个空指针作为该地址,而Fortran在任何使用中都会隐式地取消对它的引用,例如ptr = something相当于C代码*ptr = something
void test_ptr(double** ptr);是没有value属性的函数的正确等效签名。
如果您使用的是传统的Fortran 90编译器,可能会有一些与现代标准行为不匹配的怪癖或不同行为,因为value不在标准中

相关问题