[英]C - Populate a generic struct inside a function without malloc
我正在嘗試構建一個通用的 function 可以填充沒有任何動態 memory 分配的結構。
下面的代碼是我正在嘗試做的一個天真的例子。 此代碼不會編譯,因為incomplete type 'void' is not assignable
。
請注意,這是一個突出我的問題的玩具示例。 我真的不想轉換顏色; 我只是想強調一下,這些結構的數據類型和大小會有所不同。
#include <stdio.h>
typedef struct {
int r;
int g;
int b;
} rgb_t;
typedef struct {
float c;
float m;
float y;
float k;
} cmyk_t;
typedef enum { RGB, CMYK } color_t;
void convert_hex_to_color(long hex, color_t colorType, void* const out) {
if (colorType == RGB) {
rgb_t temp = { 0 };
// Insert some conversion math here....
temp.r = 1;
temp.g = 2;
temp.b = 3;
*out = temp; //< [!]
} else
if (colorType == CMYK) {
cmyk_t temp = { 0 };
// Insert some conversion math here....
temp.c = 1.0;
temp.m = 2.0;
temp.y = 3.0;
temp.k = 4.0;
*out = temp; //< [!]
}
}
int main(void) {
// Given
long hex = 348576;
rgb_t mydata = { 0 };
convert_hex_to_color(hex, RGB, (void*)(&mydata));
// Then
printf("RGB = %i,%i,%i\r\n", mydata.r, mydata.g, mydata.b);
return 0;
}
對於一些額外的上下文,我在嵌入式系統目標上使用 C11。
最好的[1]方法是什么? 宏? 聯盟?
問候,
加布里埃爾
[1] 我將“最佳”定義為可讀性和安全性之間的良好折衷。
錯誤的原因是通過void
指針存儲是無效的:編譯器不知道要存儲什么。 您可以將指針轉換為*(rgb_t *)out = temp;
或*(cmyk_t *)out = temp;
或者,您可以將temp
定義為指向適當結構類型的指針並直接從out
初始化它,而不需要 C 中不需要的強制轉換:
void convert_hex_to_color(long hex, color_t colorType, void *out) {
if (colorType == RGB) {
rgb_t *temp = out;
// Insert some conversion math here....
temp->r = 1;
temp->g = 2;
temp->b = 3;
} else
if (colorType == CMYK) {
cmyk_t *temp = out;
// Insert some conversion math here....
temp->c = 1.0;
temp->m = 2.0;
temp->y = 3.0;
temp->k = 4.0;
}
}
請注意,C 中不需要強制轉換:
int main(void) {
// Given
long hex = 348576;
rgb_t mydata = { 0 };
convert_hex_to_color(hex, RGB, &mydata);
// Then
printf("RGB = %i,%i,%i\r\n", mydata.r, mydata.g, mydata.b);
return 0;
}
rgb_t temp = {0};
這樣就在rgb_t
類型的堆棧上聲明了一個變量。 到目前為止一切順利,
盡管您不需要 0
。
*out = temp;
這是您的問題:在 C 中,您只能復制相同類型的 memory。 曾經。 正如您的標題所示,這與malloc
無關,這只是基本的語言規范。 當然,某些類型提供隱式轉換,但void*
不是其中之一。
因此,如果您要復制結構(右側的rgb_t
),則目標必須是相同的類型。 因此,將行更改為:
*(rgb_t *)out = temp;
“最好”的方法是不要在同一個 function 或同一個 memory 區域中混合不相關的結構。 那只是亂七八糟的設計。
如果您需要為兩個不同的 forms 數據保持一致的 API,那么一個類似類型安全函數的宏可能是一個想法。 您可以偽造這樣一個宏,使其具有類似於通過指針傳遞數據的語法
void convert_hex_to_color(long hex, type* data)
但隨后使用 C11 _Generic
來實際確定要使用的正確類型,而不是使用危險的 void 指針。 由於您不能“通過引用”將參數傳遞給宏,因此您必須在其中潛入變量賦值。 例子:
#include <stdio.h>
typedef struct {
int r;
int g;
int b;
} rgb_t;
typedef struct {
float c;
float m;
float y;
float k;
} cmyk_t;
void convert_hex_to_color(long hex, void* data);
/*
Pretty prototype just for code documentation purposes.
Never actually defined or called - the actual macro will "mock" this function.
*/
#define convert_hex_to_color(hex, output) ( *(output) = _Generic(*(output), \
rgb_t: (rgb_t){ .r=1, .g=2, .b=3 }, \
cmyk_t: (cmyk_t){ .c=1.0, .m=2.0, .y=3.0, .k=4.0 } ) )
int main(void) {
// Given
long hex = 348576;
rgb_t myrgb = { 0 };
cmyk_t mycmyk = { 0 };
convert_hex_to_color(hex, &myrgb);
convert_hex_to_color(hex, &mycmyk);
printf("RGB = %i,%i,%i\r\n", myrgb.r, myrgb.g, myrgb.b);
printf("CMYK = %f,%f,%f,%f\r\n", mycmyk.c, mycmyk.m, mycmyk.y, mycmyk.k);
return 0;
}
Output:
RGB = 1,2,3
CMYK = 1.000000,2.000000,3.000000,4.000000
請注意,對類型限定符( const
等)的_Generic
支持在 C11 中是不穩定的 - 一些 C11 編譯器處理const rgb_t
與rgb_t
不同,而其他編譯器則相同。 這是 C17 中的“錯誤修復”之一,因此請使用 C17(如果可用)。
幀挑戰:您似乎想要執行不同的操作,具體取決於您傳遞給此 function 的類型。 而不是使用枚舉來告訴它你傳入的是什么類型,並基於該枚舉進行分支,而是使用 C11 的_Generic
來處理它,你甚至不需要在每次調用時明確告訴它類型是什么:
#include <stdio.h>
typedef struct {
int r;
int g;
int b;
} rgb_t;
typedef struct {
float c;
float m;
float y;
float k;
} cmyk_t;
inline void convert_hex_to_color_rgb(long hex, rgb_t *const out) {
(void) hex; // or whatever you're planning to do with 'hex'
out->r = 1;
out->g = 2;
out->b = 3;
}
inline void convert_hex_to_color_cmyk(long hex, cmyk_t *const out) {
(void) hex; // or whatever you're planning to do with 'hex'
out->c = 1.0;
out->m = 2.0;
out->y = 3.0;
out->k = 4.0;
}
#define convert_hex_to_color(hex, out) _Generic((out), \
rgb_t *: convert_hex_to_color_rgb((hex), (rgb_t *)(out)), \
cmyk_t *: convert_hex_to_color_cmyk((hex), (cmyk_t *)(out)) \
)
int main(void) {
// Given
long hex = 348576;
rgb_t mydata = { 0 };
cmyk_t mydatac = { 0 };
convert_hex_to_color(hex, &mydata);
convert_hex_to_color(hex, &mydatac);
// Then
printf("RGB = %i,%i,%i\r\n", mydata.r, mydata.g, mydata.b);
printf("CMYK = %f,%f,%f,%f\r\n", mydatac.c, mydatac.m, mydatac.y, mydatac.k);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.