我一直在从事Ada项目,需要与C库(fftw3)交互。我使用了命令
gcc -c -fdump-ada-spec -C /usr/local/include/fftw3.h
生成初步绑定(需要一些调整)。我能够获取我的代码和fftw3_h.ads进行编译。但是,该程序因
崩溃raised STORAGE_ERROR : fftw3_h.ads:733 object too large
当我通过gdb运行它时,代码崩溃在定义版本字符串的一行上,
fftw_version : aliased char_array (size_t); -- /usr/local/include/fftw3.h:457
pragma Import (C, fftw_version, "fftw_version");
我对此的理解是,Ada试图一次为整个字符串分配空间,并将存储空间基于size_t的范围。但是,在这种情况下,size_t来自interfaces.c.size_t,它被定义为
type size_t is mod 2 ** System.Parameters.ptr_bits;
在i-c.ads中,而对于C,在stddef.h中将size_t定义为unsigned long。我不确定2 ** ptr_bits有多大,但是我看不出有什么理由可以预期i-c.ads中size_t的定义应限于C的无符号long的大小。如果它长于C的无符号长,那么我怀疑代码正在尝试创建一个使用比我更多的内存的数组。我试图只使用interfaces.c.unsigned_long而不是size_t,但是Ada不喜欢类型不匹配(我应该知道)。
在这一点上,我有两个问题。首先,我对问题的理解是否紧密(这是我第一次接触Ada和C之间的经验)。
第二,假设我的理解是正确的,是否有解决该问题的方法,还是我需要采取一种完全不同的方法?
答案 0 :(得分:4)
谢谢大家。西蒙的回答确实有帮助。一个问题是fftw_version []是在fftw的C代码中设置的,而不是我自己设置的,我不能保证在fftw库中的某些东西需要它之前会先调用该过程(fftw3_h.ads在我的任何代码之前都已详细说明) 。我还从Stephen J. Sangwine于2004年开始在线查找旧的FFTW_Ada绑定。虽然我无法使他的代码正常工作,但我结合了他如何处理版本字符串和Simon的建议,并创建了一个函数,该函数在fftw库中的其他内容需要时返回字符串。
function FFTW_Version return String is
tmp_version : aliased char_array(size_t) ;
pragma Import(C, tmp_version, "fftw_version");
begin
return To_Ada(tmp_version, Trim_Nul => True) ;
end FFTW_Version;
这使我可以在需要时生成字符串,但不对字符串的大小进行假设(FFTW_Ada代码就是这样做的)。这样可以编译并很好地工作。
答案 1 :(得分:3)
我认为您不了解您尝试创建的数组的大小
function uploadAjaxImages() {
$('#uploadFormAjax').off().submit(function(e) {
e.preventDefault();
// Get the selected files from the input.
var fileSelect = document.getElementById('file-select');
var files = fileSelect.files;
console.log(files);...
此行不仅说明数组fftw_version由size_t类型索引,而且还指定数组索引的范围为0..2 ** 32,这显然对于您的硬件来说太大了。 您真正想要的阵列大小是多少?例如,如果您想要一个100个字符的数组,则应指定
fftw_version : aliased char_array (size_t); -- /usr/local/include/fftw3.h:457
答案 2 :(得分:3)
引用the LRM:
int,short,long,unsigned,ptrdiff_t,size_t,double,char,wchar_t,char16_t和char32_t类型分别对应于具有相同名称的C类型。
无论实际定义如何,您都可以相信编译器遵守LRM,因此Ada的size_t
实际上具有与C完全相同的大小。
话虽如此,您的错误源于以下事实:在为数组分配size_t'Last
字节时,您会得到堆栈溢出。我在fftw3.h
标头中搜索了您要包装的fftw_version
的定义,但找不到任何定义,因此,要获得更详细的答案,您需要显示您所需要的代码包装。您很可能想用chars_ptr
代替Interfaces.C.Strings来包装C语言中的字符串-它的转换方法要通过搜索空终止符来获取字符串的长度。
答案 3 :(得分:3)
在我看来,这很可能是您在使用它。这不是Minimal, Complete and Verifiable Example,因为它对我有用:-)
bartels.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
procedure Bartels is
fftw_version : aliased char_array (size_t); -- /usr/local/include/fftw3.h:457
pragma Import (C, fftw_version, "fftw_version");
V : constant String := To_Ada (fftw_version, Trim_Nul => True);
begin
Put_Line (V);
end Bartels;
bartels_c.c:
const char fftw_version[] = "the version";
编译C文件,使用构建Ada
$ gnatmake bartels.adb -largs bartels_c.o
然后运行
$ ./bartels
the version
答案 4 :(得分:1)
@Jim Rogers总结了几个有用的答案,指出here涉及size_t
对象的详细说明可能超出了可用内存。 @Simon Wright观察到here并说明here,无需为导入的对象分配空间。实际上,相应的Import
所暗示的pragma方面规定了以下动态语义:
尽管本国际标准在其他地方说了什么,但对具有“真正导入”方面的声明的详细说明不会创建实体。除了允许定义名称表示外部实体之外,这种详细说明没有其他作用。
以下完整示例说明了与@C在function
中here所示的用法对应的方面。 Bartels:
控制台:
$ gprclean -q ; gprbuild -q && ./bartels
Versioni 1.2.3
bartels.gpr:
project Bartels is
for Languages use ("Ada", "C");
for Main use ("bartels.adb");
end Bartels;
bartels.adb:
with Ada.Text_IO;
with Interfaces.C;
procedure Bartels is
function Get_Version return String is
version : Interfaces.C.char_array(Interfaces.C.size_t)
with Import => True, Convention => C;
begin
return Interfaces.C.To_Ada(version, Trim_Nul => True) ;
end Get_Version;
begin
Ada.Text_IO.Put_Line (Get_Version);
end Bartels;
version.c:
const char version[] = "Versioni 1.2.3";
顺便说一句,由于此示例适用于GNAT Community 2018
,但不适用于GNAT GPL 2017
时,可能会引起一些困惑:
$ gprclean -q ; gprbuild -q && ./bartels
raised STORAGE_ERROR : bartels.adb:7 object too large