Reputation: 5827
Let in C code are defined:
typedef enum { A=1, B=2 } option_type; void f(option_type option);
Let we also have Ada code:
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;
Which of the following code is correct (accordingly RM)?
-- First code
declare procedure F (Option: Option_Type) with Import, Convention=>C, External_Name=>"f"; begin F(X); end;
or
-- Second code
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;
I think both first and second Ada fragments are correct but am not sure.
Upvotes: 3
Views: 1394
Reputation: 263657
Neither is 100% correct.
In C:
typedef enum { A=1, B=2 } option_type;
In Ada:
type Option_Type is (A, B);
for Option_Type'Size use Interfaces.C.int'Size;
for Option_Type use (A=>1, B=>2);
The Ada code assumes that the C type option_type
has the same size as a C int
. Your second snippet assumes it has the same representation as a C unsigned int
.
Neither assumption is supported by the C standard.
Quoting the N1570 draft, section 6.7.2.2, paragraph 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.
So the C type option_type
could be as narrow as 1 byte or as wide as the widest supported integer type (typically 8 bytes), and it could be either signed or unsigned. C restricts the values of the enumeration constants to the range of type int
, but that doesn't imply that the type itself is compatible with int
-- or with unsigned int
.
If you have knowledge of the characteristics of the particular C compiler you're using (the phrase "implementation-defined" means that those characteristics must be documented), then you can rely on those characteristics -- but your code is going to be non-portable.
I'm not aware of any completely portable way to define an Ada type that's compatible with a given C enumeration type. (I've been away from Ada for a long time, so I could be missing something.)
The only portable approach I can think of is to write a C wrapper function that takes an argument of a specified integer type and calls f()
. The conversion from the integer type to option_type
is then handled by the C compiler, and the wrapper exposes a function with an argument of known type to Ada.
void f_wrapper(int option) {
f(option); /* the conversion from int to option_type is implicit */
}
Upvotes: 5