提问人:user1806687 提问时间:8/27/2022 最后编辑:user1806687 更新时间:8/27/2022 访问量:192
C 语言中的泛型类型转换
Generic type conversion in C
问:
我有一个数据类型列表()。我想自动(使用 X 宏)创建从其中一种类型转换为另一种类型的函数。STANDARD_TYPES
我有以下代码:
#define STANDARD_TYPES(macro) \
macro(char) \
macro(uchar) \
macro(schar) \
macro(short) \
macro(ushort) \
macro(int) \
macro(uint) \
macro(long) \
macro(ulong) \
macro(longlong) \
macro(ulonglong) \
macro(float) \
macro(double) \
macro(longdouble)
#define Y(to_type, from_type) \
case TYPE_##from_type: \
((struct result_##to_type *)result)->value = \
(to_type)((struct result_##from_type *)result)->value; \
break;
#define X(to_type) \
void convert_to_##to_type(struct result *result) \
{ \
switch (result->type) { \
Y(to_type, long) \
} \
\
return result; \
}
STANDARD_TYPES(X)
#undef X
#undef Y
struct result_X
为每种类型生成,如下所示:
struct result {
enum type type;
};
struct result_char {
enum type type;
char value;
};
struct result_long {
enum type type;
long value;
};
通过上面的代码示例,我可以生成从数据类型转换为任何其他数据类型的函数。例如,上述代码示例的输出为:char
long
void convert_to_long(struct result *result)
{
switch (result->type) {
case TYPE_char:
((struct result_long *)result)->value = (long)((struct result_char *)result)->value;
break;
}
}
我可以用什么替换代码或代码的更多部分,使其在所有定义的数据类型之间生成转换函数?Y(to_type, char)
编辑:
enum type {
TYPE_char,
TYPE_uchar,
TYPE_schar,
...
TYPE_long,
...
};
编辑2:
为了澄清一些事情,我将简要解释我的代码试图实现的目标。在用户端,也就是使用我的代码的人,他们正在执行一些数学运算,完成后,他们将结果与结果的类型和值一起写入。struct result *result
然后,我的代码应将 的值从包含的类型转换为请求的类型,该类型可以是任何标准类型。struct result *result
struct result *result
void convert_result(struct result *result, enum type new_type)
{
switch (new_type) {
case TYPE_char:
convert_to_char(result);
break;
...
case TYPE_long:
convert_to_long(result);
break;
};
答:
当您违反严格的别名规则时,您的代码会调用未定义的行为。
要“转换”(它称为类型双关)char数组到其他类型(假设汽车数组包含目标类型的正确字节表示)玩具需要它。此外,您的奇怪枚举也无法正常工作。memcpy
例:
long long puneToLongLong(const char *buff)
{
long long result;
memcpy(&result, buff, sizeof(result));
return result;
}
double puneToDouble(const char *buff)
{
double result;
memcpy(&result, buff, sizeof(result));
return result;
}
int puneTo(const char *buff)
{
int result;
memcpy(&result, buff, sizeof(result));
return result;
}
int main(void)
{
char cd[sizeof(double)];
char cll[sizeof(long long)];
char ci[sizeof(int)];
memcpy(cd, &(double){5.45676545}, sizeof(cd));
memcpy(cll, &(long long){453676457654}, sizeof(cll));
memcpy(ci, &(long long){-12454354}, sizeof(ci));
printf("%f\n", puneToDouble(cd));
printf("%lld\n", puneToLongLong(cll));
printf("%i\n", puneToInt(ci));
}
评论
我认为没有办法获得在自身内部应用 X 宏的所需行为,因为递归宏替换被 C 2018 6.10.3.4 2 抑制了。但是,如果定义两个 X 宏,则可以执行以下操作:
#define ApplyToTypes(macro) \
macro(char) \
macro(short) \
macro(int)
#define ApplyToTypes2(ToType, macro) \
macro(ToType, char) \
macro(ToType, short) \
macro(ToType, int)
#define Case(ToType, FromType) \
case TYPE_##FromType: \
((struct result_##ToType *) result)->value = \
(ToType) ((struct result_##FromType *) result)->value; \
break;
#define Routine(ToType) \
void ConvertTo##ToType(struct result *result) \
{ \
switch (result->type) \
{ \
ApplyToTypes2(ToType, Case) \
} \
}
ApplyToTypes(Routine)
这被替换为(为了便于阅读,添加了手动格式):
void ConvertTochar(struct result *result)
{
switch (result->type)
{
case TYPE_char: ((struct result_char *) result)->value = (char) ((struct result_char *) result)->value;
break;
case TYPE_short: ((struct result_char *) result)->value = (char) ((struct result_short *) result)->value;
break;
case TYPE_int: ((struct result_char *) result)->value = (char) ((struct result_int *) result)->value;
break;
}
}
void ConvertToshort(struct result *result)
{
switch (result->type)
{
case TYPE_char: ((struct result_short *) result)->value = (short) ((struct result_char *) result)->value;
break;
case TYPE_short: ((struct result_short *) result)->value = (short) ((struct result_short *) result)->value;
break;
case TYPE_int: ((struct result_short *) result)->value = (short) ((struct result_int *) result)->value;
break;
}
}
void ConvertToint(struct result *result)
{
switch (result->type)
{
case TYPE_char: ((struct result_int *) result)->value = (int) ((struct result_char *) result)->value;
break;
case TYPE_short: ((struct result_int *) result)->value = (int) ((struct result_short *) result)->value;
break;
case TYPE_int: ((struct result_int *) result)->value = (int) ((struct result_int *) result)->value;
break;
}
}
要提供由 C 标准定义的此代码行为,您可以定义一个包含所有结构的联合,以便 C 2018 6.5.2.3 6 适用。1 但是,简单地定义一个包含联合的结构并重写代码以匹配可能会更好:result
struct result
{
enum type type;
union
{
char char_value;
short short_value;
int int_value;
…
};
};
例如:
#define ApplyToTypes(macro) \
macro(char) \
macro(short) \
macro(int)
#define ApplyToTypes2(ToType, macro) \
macro(ToType, char) \
macro(ToType, short) \
macro(ToType, int)
#define DeclareEnumConstants(Type) Type##Enum,
enum type { ApplyToTypes(DeclareEnumConstants) };
#define DeclareMember(Type) Type Type##Value;
struct result
{
enum type type;
union
{
ApplyToTypes(DeclareMember)
};
};
#define Case(ToType, FromType) \
case FromType##Enum: \
result->ToType##Value = (ToType) result->FromType##Value; \
break;
#define Routine(ToType) \
void ConvertTo##ToType(struct result *result) \
{ \
switch (result->type) \
{ \
ApplyToTypes2(ToType, Case) \
} \
}
ApplyToTypes(Routine)
脚注
1 C 2018 6.5.2.3 6说道:
...如果一个并集包含多个共享一个共同初始序列的结构...,则允许在可见并集完整类型的声明的任何地方检查其中任何一个的共同初始部分...
同样相关的还有C 2018 67.2.1 16:
...指向联合对象的指针(经过适当转换)指向其每个成员(或者,如果成员是位域,则指向它所在的单元),反之亦然。
评论
long double
bool
struct result_custom { enum type type; /* custom members */ };
ConvertTo
struct result
enum type
enum type
struct_result_char
struct result
struct result
struct result_char
enum type
评论
struct result
char
char*
long
result