我经常需要处理 C 中
enum
的功能。然而,似乎没有一种简单且同样有效的方法来根据预定义的 enum
值提供不同的结果——至少,不适合我的情况。采取以下代码:
/**
* @brief An enumerator to represent all the various numerical types that
* can be stored in the @ref dynamic_array_number_t. This is simply a list
* of the various integer types that can fit into a signed 64-bit integer.
*/
typedef enum
{
/**
* @brief Unsigned 8-bit integer.
*/
unsigned8,
/**
* @brief Unsigned 16-bit integer.
*/
unsigned16,
/**
* @brief Unsigned 32-bit integer.
*/
unsigned32,
/**
* @brief Signed 8-bit integer.
*/
signed8,
/**
* @brief Signed 16-bit integer.
*/
signed16,
/**
* @brief Signed 32-bit integer.
*/
signed32
} dynamic_array_number_type_t;
/**
* @brief A dynamic array for integers. Can store an infinite amount of
* members, if your computer's got the memory. All functions having to do
* with this type are suffixed with "-N".
*/
typedef struct
{
/**
* @brief The list of the array's members. Stored in 8 bytes (64 bits)
* since it provides integer safety, along with being a sort of generic
* for all the possible integer types. Do not mess with this value
* yourself, use helper functions. Do not retrieve values within this
* array yourself, use helper functions.
*/
int64_t* members;
/**
* @brief The type of integer we're storing in the array. This cannot
* change, and is therefore marked with const. See @ref
* dynamic_array_number_type_t for more information.
*/
const dynamic_array_number_type_t type;
/**
* @brief The size of the array (in 64-bit blocks of memory). This is
* simply a counter of how many numbers it @b can store, not @b is
* storing. That is stored in the @ref occupied value. Do not increment
* this value yourself, use helper functions.
*/
size_t size;
/**
* @brief The count of members within the array. Do not mess with this
* value, the program will very nearly always crash. Use helper
* functions.
*/
uint32_t occupied;
} dynamic_array_number_t;
/**
* @brief Allocate a block of memory of @param size bytes long. This is
* legitimately just @ref xmalloc but with a name that fits my scheme.
* @param size The size--in bytes--of the block to allocate.
* @return A pointer to to newly allocated block.
*/
void* AllocateBlock(size_t size);
/**
* @brief Create a new dynamic array for integer types. You must free the
* object returned by this function with @ref DestroyDynamicArrayN.
* @param type The integer type this array should contain when converted
* from the default int64_t.
* @param size The size the array should be off the bat; this can be
* changed via helper functions like @ref GrowDynamicArrayN or @ref
* ShrinkDynamicArrayN.
* @return A brand-spanking-new integer dynamic array.
*/
inline static dynamic_array_number_t
CreateArrayN(dynamic_array_number_type_t type, size_t size)
{
return (dynamic_array_number_t){AllocateBlock(sizeof(int64_t) * size),
type, size, 0};
}
/**
* @brief Destroy the given integer array. The array passed into this
* function, upon the completion of it, shall have none of its prior data
* beyond the value of its @ref type member, and all deleted data shall
* have been destroyed irretrievably.
* @param array The array to destroy.
*/
void DestroyArrayN(dynamic_array_number_t* array);
// This is in a separate C file.
void* AllocateBlock(length_t size)
{
void* ptr = malloc(size);
if (ptr == NULL) LogError(failed_allocation);
return ptr;
}
void DestroyArrayN(dynamic_array_number_t* array)
{
assert(array != NULL && array->members != NULL);
free(array->members);
array->members = NULL;
array->size = 0;
array->occupied = 0;
}
以及数组创建的示例:
int main(void) {
dynamic_array_number_t test_array = CreateArrayN(unsigned8, 3);
// ... do stuff with array
DestroyArrayN(&test_array);
return 0;
}
我需要将结构中的
int64_t
转换为用户在创建数组时提供给数组的任何整数类型,uint8_t
,int32_t
,等等。当然,这很容易,使用像 (int8_t)array.members[0]
这样的简单转换。然而,我想提供一个辅助函数来使这种访问更容易,但我不想只返回一个 int64_t
就到此为止;这似乎毫无意义。
相反,有没有一种方法(类似于类型的 _Generic 语句)可以为传入数组的
type
值的任何可能值提供不同的函数?
有没有一种方法(类似于类型的 _Generic 语句)可以为传入数组的类型值的任何可能值提供不同的函数?
不。类似于 unsigned8
或
unsigned16
的枚举 value是运行时可用的信息,但 type 是编译时可用的信息。您无法进行时间旅行 - 一旦您使用在运行时具有值的value,它就不会影响编译时的类型。
如果您想要在编译时获得类型信息,则必须在编译时提供该信息。通常,人们会在编译时使用不同的 types 来表示该信息,例如
struct dynamic_array_signed8
struct dynamic_array_unsigned8
等。您可能对 STC 库感兴趣。
总的来说,使用 enum 值来表示不同的 types 是一个坏主意,这会导致超长的切换:https://github.com/Gurux/GuruxDLMS.c/blob/master/development/src /gxobjects.c#L1323 。您可能对虚拟方法 https://en.wikipedia.org/wiki/Virtual_method_table 非常感兴趣,以在运行时实现对象特定的动态调度。