让C代码定义:
typedef enum { A=1, B=2 } option_type; void f(option_type option);
我们也有Ada代码:
type Option_Type is (A, B); for Option_Type'Size use Interfaces.C.int'Size; for Option_Type use (A=>1, B=>2); X: Option_Type := A;
以下哪个代码是正确的(相应的RM)?
- 第一个代码
declare procedure F (Option: Option_Type) with Import, Convention=>C, External_Name=>"f"; begin F(X); end;
或
- 第二个代码
declare procedure F (Option: Interfaces.C.unsigned) with Import, Convention=>C, External_Name=>"f"; function Conv is new Ada.Unchecked_Conversion(Option_Type, Interfaces.C.unsigned); begin F(Conv(X)); end;
我认为第一和第二个Ada片段都是正确的,但我不确定。
答案 0 :(得分:4)
两者都不是100%正确。
在C:
typedef enum { A=1, B=2 } option_type;
在阿达:
type Option_Type is (A, B);
for Option_Type'Size use Interfaces.C.int'Size;
for Option_Type use (A=>1, B=>2);
Ada代码假定C类型option_type
与C int
具有相同的大小。您的第二个代码段假定它与C unsigned int
具有相同的表示形式。
C标准都不支持这两种假设。
引用N1570草案,第6.7.2.2节,第4段:
每个枚举类型都应与
char
兼容 整数类型或无符号整数类型。类型的选择是 实现定义,但应能够代表 枚举的所有成员的值。
因此C类型option_type
可以窄至1字节或宽度与最广泛支持的整数类型(通常为8字节),并且可以是有符号或无符号。 C将枚举常量的值限制为int
类型的范围,但这并不意味着类型本身与int
- 或与unsigned int
兼容。< / p>
如果您了解您正在使用的特定C编译器的特性(短语&#34;实现定义&#34;意味着必须记录这些特征),那么您可以依赖这些特征 - 但是你的代码将是不可移植的。
我不知道任何完全可移植的方式来定义与给定C枚举类型兼容的Ada类型。 (我已经离开阿达很长一段时间了,所以我可能会错过一些东西。)
我能想到的唯一可移植方法是编写一个C包装函数,该函数接受指定整数类型的参数并调用f()
。然后,由C编译器处理从整数类型到option_type
的转换,并且包装器向Ada公开具有已知类型的参数的函数。
void f_wrapper(int option) {
f(option); /* the conversion from int to option_type is implicit */
}