簡體   English   中英

C - 在沒有 malloc 的 function 內填充通用結構

[英]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_trgb_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM