簡體   English   中英

通過 memcpy 將“指向 const 的指針”復制到“指向非 const 的指針”

[英]Copy “pointer to const” to “pointer to non const” via memcpy

const void *a = something;
void *b = a;

返回警告:

警告:初始化從指針目標類型中丟棄“const”限定符 [-Wdiscarded-qualifiers]

通過memcpy將指向const的指針復制到指向非const的指針以避免警告是否安全(定義明確的行為)?

/* Linear search */
void *vector_lsearch(const void *key, const void *base, int (*comp)(const void *, const void *))
{
    const struct vector *vector = CONST_VECTOR(base);
    void *cast[1];
    void *data;

    /* Skip const to non const warning */
    data = *(void **)memcpy(cast, &base, sizeof base);

    for (size_t item = 0; item < vector->size; item++)
    {
        if (comp(data, key) == 0)
        {
            return data;
        }
        data = (unsigned char *)data + vector->szof;
    }
    return NULL;
}

該警告來自於將 const 限定符作為初始化的一部分。 只需添加顯式演員表也可以避免警告。

const void *a = something;
void *b = (void *)a;

該標准的第 6.5.4 節描述了對指針隱式轉換的約束:

涉及指針的轉換,除了 6.5.16.1 的約束允許的情況外,應通過顯式轉換來指定。

顯式轉換指針的唯一限制是:

指針類型不應轉換為任何浮點類型。 浮動類型不應轉換為任何指針類型。

第一條規則 6.5.16.1 的相關部分具有以下簡單分配規則:

左操作數具有原子、限定或非限定指針類型,並且(考慮左操作數在左值轉換后將具有的類型)兩個操作數都是指向兼容類型的限定或非限定版本的指針,並且左側指向的類型具有所有右邊指向的類型的限定符;

最后,關於限定符的第 6.7.3 節有:

如果嘗試通過使用具有非 const 限定類型的左值來修改使用 const 限定類型定義的 object,則行為未定義。

如果具有非 const 限定類型的左值可以訪問使用 const 限定類型定義的對象,那么這句話不會提供太多價值。 這表明您可以將 const void * 顯式轉換為 void * 並避免警告而不會引入未定義的行為,因為警告特別涉及通過簡單賦值對隱式轉換的無效使用,而不是一般反對丟棄 const 限定符。

復制指針是安全的。 潛在的安全問題是當您使用b時。 由於它被聲明為指向非常量數據的指針,因此您可以通過指針進行賦值,例如*(int *b) = 1; 如果something是常量數據,這將導致未定義的行為。

如果您使用void *指針作為最終將指針傳遞給 function 的管道,該指針會將指針轉換回其原始類型(就像qsort()使用其指針參數的方式一樣),您應該能夠忽略這個警告。 您會期望 function 將其轉換回指向const的指針,而不是嘗試通過它進行分配。

我不認為有一種方法可以聲明一個可以用作 const 或非常量數據的管道的通用指針。 如果您將其聲明為非 const,則在為它分配 const 指針時會收到警告; 如果您將其聲明為 const,您將無法將其用於需要非常量指針的函數。

初始化void *b = a; 是無效的 C,它違反了簡單賦值規則 C17 6.5.16.1(初始化遵循賦值規則),其中規定為了使表達式有效:

...左側指向的類型具有右側指向的類型的所有限定符。

您可能希望使用-pedantic-errors進行編譯以獲取錯誤而不是針對 C 語言違規的警告。


至於定義明確的行為——只要你使用正確類型的實際數據取消引用指針,它就是明確定義的行為,指針本身的類型並不重要。

我什至不明白你為什么需要轉換為void* ,因為你的回調格式是這樣的:

int (*comp)(const void *, const void *)

所以唯一的問題是外部 function 的返回類型,可以簡化為這樣的:

void* vector_lsearch (const void* key, const void* base, int (*comp)(const void*, const void*))
{
    const struct vector* vector = CONST_VECTOR(base);
    void* result = NULL;
    unsigned char* data = (unsigned char*)base;

    for (size_t i=0; i < vector->size; i++)
    {
        if (comp(&data[i*vector->szof], key) == 0)
        {
            result = data;
            break;
        }
    }
    return result;
}

CONST_VECTOR是可疑的,聞起來像你在宏或什么后面隱藏一個演員?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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