让我们在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 片段都是正确的,但我不确定。
最佳答案
两者都不是 100% 正确。
在 C 中:
typedef enum { A=1, B=2 } option_type;
在 Ada 中:
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 段:
Each enumerated type shall be compatible with
char
, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.
因此 C 类型 option_type
可以窄到 1 个字节,也可以宽到支持的最宽整数类型(通常为 8 个字节),并且它可以是有符号的或无符号的。 C 将枚举常量的值限制在 int
类型的范围内,但这并不意味着该类型本身与 int
或 兼容无符号整型
。
如果您了解正在使用的特定 C 编译器的特性(短语“实现定义”意味着必须记录这些特性),那么您可以依赖这些特性——但您的代码将不可携带。
我不知道有任何完全可移植的方法来定义与给定的 C 枚举类型兼容的 Ada 类型。 (我已经离开 Ada 很长时间了,所以我可能会遗漏一些东西。)
我能想到的唯一可移植方法是编写一个 C 包装函数,它接受指定整数类型的参数并调用 f()
。然后由 C 编译器处理从整数类型到 option_type
的转换,包装器向 Ada 公开一个带有已知类型参数的函数。
void f_wrapper(int option) {
f(option); /* the conversion from int to option_type is implicit */
}
关于enums - 连接 Ada 枚举和 C 枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25353190/