簡體   English   中英

為什么在使用其值之前必須將void指針轉換為int指針?

[英]Why I have to cast void pointer to int pointer before using its value?

所以我今天遇到了這種情況。 我有這樣的代碼

void some_handler(some_stuct_t * p_evt_type)
{   
            uint16_t a = ((uint16_t )p_evt_type->p_instance->p_instance_handler);
            (a)++;
}

這是給我的警告,但是當我將代碼更改為強制轉換為指針時,它看起來完全正確。

void some_handler(some_stuct_t * p_evt_type)
{   
            uint16_t * a = ((uint16_t *)p_evt_type->p_instance->p_instance_handler);
            (*a)++;
}

p_instance_handler

是類型

(void *)

直接鑄就價值有什么問題?

INT36-C。 將指針轉換為整數或將整數轉換為指針

根據實現的不同,整數和指針之間的轉換可能會產生不良后果。 根據C標准第6.3.2.3節[ ISO / IEC 9899:2011 ],

整數可以轉換為任何指針類型。 除非先前指定,否則結果是實現定義的,可能未正確對齊,可能未指向引用類型的實體,並且可能是陷阱表示。

任何指針類型都可以轉換為整數類型。 除非先前指定,否則結果是實現定義的。 如果結果不能用整數類型表示,則行為是不確定的。 結果不必在任何整數類型的值范圍內。

簡而言之,可以在指針和整數之間進行轉換,但是結果是實現定義的,因此在sizeof(integer) < sizeof(pointer)的實現中,轉換將不起作用。

不兼容的代碼示例

指針的大小可以大於整數的大小,例如在指針為64位而無符號整數為32位的實現中。

 void f(void) { char *ptr; /* ... */ unsigned int number = (unsigned int)ptr; /* ... */ } 

盡管無需將指針從類型轉換為void或將void轉換為類型 (此處有一些有限的例外情況不相關),但當您需要取消引用void指針時,轉換就變得至關重要。 如您所知,指針將其他地址存儲為其值。 當處理與該值相同類型的指針時,由於該type已經固定,因此不需要任何其他強制type轉換。 例如

int a[] = { 1, 3, 5, 7, 9 };
int *ap = a;
ap++;
printif (" ap points to : %d\n", *ap);

一切都很好,沒有神秘感。 現在,讓我們使用一個函數,該函數將使用數組和元素數量作為參數來迭代數組中的值。 但是,仍然需要另一個參數才能迭代作為void *傳遞的數組。 它是什么? sizeof運算,使每一個元素燮a

否則,由於數組作為空指針傳遞, 指針算術會發生什么? 在函數中,如果我們嘗試ap++會發生什么?

問題就在這里。 當將指針作為空指針處理時,它們非常方便使用,但是當必須對它們持有的值進行操作時,必須對其進行強制轉換,以便編譯器知道所指向的對象的大小,從而可以知道ap之間存在多少字節。數組中的下一個值位於ap++

類型轉換指針還有另一個警告。 必須以不違反嚴格別名規則並且不會發生類型調整的方式來強制轉換它們 請參閱C11 N1570委員會草案-2011年4月12日。為此,您將要仔細閱讀第6.5(6)和(7)節,並密切注意草案中包含的注釋。 無需研究漏洞和限定條件,您就可以安全地將void指針強制轉換為其有效類型char 任何其他組合都要求別名混疊違規,從而導致類型為指針的指針。

因此,繼續我們的示例,如果將數組a作為void *而不是int *傳遞給函數,則函數中需要什么才能使指針算法正常工作? 從規則6.5(6)知道,我們可以強制轉換為char而不違反嚴格別名規則,因此我們可以像這樣處理它,其中a是我們的數組, n個元素的個數和sz數組中每個元素的大小:

void prnarray (void *a, size_t n, size_t sz)
{
    char *ap = a;
    printf ("\npointers printed from prnarray:\n\n");
    while (n--) {
        printf (" ap points to : %d\n", *ap);
        ap += sz;
    }
}

然后,我們可以毫無問題地逐步遍歷數組,同時為每個先前的元素添加適當的大小/偏移量。

如果我們知道我們將通過void指針獲取一個int數組怎么辦? 這樣就可以將類型直接轉換為有效的數組類型 ,而我們不再需要擔心傳遞大小。 指針算法將照顧到數組中每個值的偏移量,例如

 void prnarrayint (void *a, size_t n)
{
    int *ap = a;
    printf ("\npointers printed from prnarrayint:\n\n");
    while (n--)
        printf (" ap points to : %d\n", *ap++);
}

盡管不像以前的函數那樣靈活,但我們不僅限於類型,但在許多情況下,您會知道要傳遞的指針類型為void,在這種情況下,強制轉換為有效類型將簡化您的操作。碼。

現在將所有部分放在一起,您可以創建一個簡短的說明性示例,如下所示:

#include <stdio.h>

void prnarray (void *a, size_t n, size_t sz)
{
    char *ap = a;
    printf ("\npointers printed from prnarray:\n\n");
    while (n--) {
        printf (" ap points to : %d\n", *ap);
        ap += sz;
    }
}

void prnarrayint (void *a, size_t n)
{
    int *ap = a;
    printf ("\npointers printed from prnarrayint:\n\n");
    while (n--)
        printf (" ap points to : %d\n", *ap++);
}

int main (void) {

    int a[] = { 1, 3, 5, 7, 9 };
    int *ap = a;
    size_t i, n = sizeof a/ sizeof *a;
    i = n;

    printf ("\npointers printed in main:\n\n");
    while (i--)
        printf (" ap points to : %d\n", *ap++);

    prnarray (a, n, sizeof *a);  /* pass/print based on sz with cast to char */

    prnarrayint (a, n);  /* pass/print based on effective type of array */

    return 0;
}

使用/輸出

$ ./bin/voidpcast

pointers printed in main:

 ap points to : 1
 ap points to : 3
 ap points to : 5
 ap points to : 7
 ap points to : 9

pointers printed from prnarray:

 ap points to : 1
 ap points to : 3
 ap points to : 5
 ap points to : 7
 ap points to : 9

pointers printed from prnarrayint:

 ap points to : 1
 ap points to : 3
 ap points to : 5
 ap points to : 7
 ap points to : 9

因此,總而言之,可以將通用指針void分配給任何類型的指針,或從任何類型的指針分配通用指針void ,而無需進行強制轉換,但是,如果任何操作都需要取消對指針的引用以獲得指向的值,則必須進行適當的強制轉換更改為有效類型char ,以符合嚴格混疊的規則。

暫無
暫無

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

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