好的,这将是一个很长的,我提前为此道歉。 =)
我需要指出的是,由于保密原因,此处使用的代码与实际生产代码并不完全匹配,但是用于说明问题,一些经过测试的解决方案以及促进讨论。在概念层面上,虽然所有内容都已被删除和简化,但它足够相似。数据保护虽然在现实中是必要的,但在这里却被忽略了。
我们有一个共享对象'data_provider',它是从Ada代码生成的。 Data_provider有一个内部数据记录,我们需要从许多共享对象访问'data_user'1到n,也是从(不同的)Ada代码生成的。这些共享包含类型defs的Ada规范,但实际上数据需要在共享对象边界之间共享,最好不要进行不必要的复制(有效;估计和基准测试)性能原因。
这些共享对象通过libdl链接到c ++主程序(此处称为'wrapper'),无论是编译时还是运行时(这还不是一成不变的),因此解决方案需要工作无论哪种方式。我应该补充一点,如果可以从c ++端检查数据也是有益的,即使我们没有可用的完整类型def。
代码可能需要通过Ada95编译,尽管-05 可能可以工作。 -12不在桌面上。平台是RHEL5上的GNAT。
目前,“工作”解决方案是简单地获取数据记录的地址,将其传递给包装器,将其传递给data_user对象,在那里转换地址>访问,并将指针数据复制到内部对象。这是下面的示例代码中实现的方法。但是额外的副本可能在性能方面存在问题。
另一个“有效”的测试方法是简单地让data_provider导出变量,data_users导入变量,但这要求它们在编译时都被链接,并且它还会全局公开数据,这让我觉得很脏,更不用说它很脆弱了。
我相信for data'address use addr
条款需要在详细时间知道地址,因此不起作用..?
其他一些事情已被尝试并被丢弃,但我现在暂时离开他们。
我希望结合下面的代码足以得到一些建议;我听见了。如果有任何需要澄清的话,请索取。 =)
我其实很希望我只是愚蠢而且在这里遗漏了一些明显的东西。我确实意识到,在Ada或其他方面,整个混乱并不完全遵循良好的编码习惯,但我仍然有点坚持。
extern "C" {
void update_data( int fa, int fb );
int get_address( void );
void set_address( int addr );
void handle_new_data( void );
}
int main( int argc, char** argv ) {
int addr;
addr = get_address();
set_address( addr );
for (int i = 0; i < 42; i++) {
update_data( i, -i );
handle_new_data();
}
}
package data_types is
-- dummy data type
-- SIMPLIFIED from actual use case
type data_t is
record
field_a : integer := 16#c0ffee#;
field_b : integer := 16#c0ffee#;
end record;
for data_t use
record
field_a at 0 range 0..31;
field_b at 4 range 0..31;
end record;
type data_t_ptr is access data_t;
end data_types;
with system,
data_types;
use system,
data_types;
package data_provider is
-- update internal data structure
-- SIMPLIFIED from actual use case
procedure update_data
( fa : in integer;
fb : in integer );
pragma export_procedure
( internal => update_data,
external => "update_data" );
-- return address to record containing data
function get_address return system.address;
pragma export_function
( internal => get_address,
external => "get_address" );
-- 'dummy' data; this needs to be passed to data_user
data : data_t;
end data_provider;
with system;
use system;
package body data_provider
is
procedure update_data
( fa : in integer;
fb : in integer )
is
begin
data.field_a := fa;
data.field_b := fb;
end ;
function get_address return system.address
is
begin
return data'address;
end;
end data_provider;
with system,
data_types;
use system,
data_types;
package data_user
is
-- set address for the data record
procedure set_address
( addr : system.address );
pragma export_procedure
( internal => set_address,
external => "set_address" );
-- use the new data in internal data structure
-- SIMPLIFIED from actual use case
procedure handle_new_data;
pragma export_procedure
( internal => handle_new_data,
external => "handle_new_data" );
-- 'dummy' data; this needs to be passed from data_provider
data : data_t;
end data_user;
with system,
unchecked_conversion,
data_types;
use system,
data_types;
package body data_user
is
function to_ptr is new unchecked_conversion
( source => system.address,
target => data_t_ptr );
-- set address for the data record
procedure set_address
( addr : system.address )
is
ptr : data_t_ptr;
begin
ptr := to_ptr( addr );
data := ptr.all;
end;
-- use the new data in internal data structure
-- SIMPLIFIED from actual use case
procedure handle_new_data
is
begin
null;
end;
end data_user;
用Ada编写并从C ++外部调用的多个共享库需要访问存储在Ada记录中的相同数据,最好不要复制。我该怎么做?
答案 0 :(得分:4)
将数据复制到用户的唯一位置是Data_User.Set_Address
。致Data_Provider.Update_Data
的电话会更改Data_Provider
中的副本,但不会对任何用户产生任何影响。
为什么不让Set_Address
存储指针,然后Handle_New_Data
读取它?
package data_user
is
-- as before
data_ptr : data_t_ptr;
end data_user;
.......
package body data_user
is
.....
-- set address for the data record
procedure set_address
( addr : system.address )
is
begin
data_ptr := to_ptr( addr );
end;
procedure handle_new_data
is
begin
-- work with data_ptr.all
end;
end data_user;
顺便说一句,您应该使用System.Address_To_Access_Conversions
而不是Unchecked_Conversion
来完成这项工作。