簡體   English   中英

C中void指針的指針算法

[英]Pointer arithmetic for void pointer in C

當指向特定類型(例如intcharfloat 、 ..)的指針遞增時,其值會增加該數據類型的大小。 如果指向大小為x數據的void指針遞增,它如何指向前面的x個字節? 編譯器如何知道將x添加到指針的值?

最終結論:對void*算術在 C 和 C++ 中都是非法的

GCC 允許將其作為擴展,參見 關於void和函數指針的算術(注意本節是手冊“C 擴展”一章的一部分)。 為了與 GCC 兼容,Clang 和 ICC 可能允許void*算術。 其他編譯器(例如 MSVC)不允許對void*算術運算,如果指定了-pedantic-errors標志,或者指定了-Werror-pointer-arith標志(如果您的代碼庫也必須用 MSVC 編譯)。

C 標准說話

引自 n1256 草案。

該標准對加法運算的描述指出:

6.5.6-2:對於加法,要么兩個操作數都為算術類型,要么一個操作數為指向對象類型的指針,另一個操作數為整數類型。

所以,這里的問題是void*是否是指向“對象類型”的指針,或者等價地, void是否是“對象類型”。 “對象類型”的定義是:

6.2.5.1:類型分為對象類型(完整描述對象的類型)、函數類型(描述函數的類型)和不完整類型(描述對象但缺少確定其大小所需的信息的類型)。

該標准將void定義為:

6.2.5-19: void類型包含一組空值; 它是無法完成的不完整類型。

由於void是不完整的類型,因此它不是對象類型。 因此,它不是加法運算的有效操作數。

因此,您不能對void指針執行指針運算。

筆記

最初,人們認為void*算術是允許的,因為 C 標准的這些部分:

6.2.5-27:指向 void 的指針應具有指向字符類型的指針相同的表示和對齊要求。

然而,

相同的表示和對齊要求意味着作為函數的參數、函數的返回值和聯合成員的可互換性。

所以這意味着printf("%s", x)無論x類型是char*還是void*都具有相同的含義,但這並不意味着您可以對void*進行算術運算。

void*指針上不允許進行指針運算。

將其強制轉換為 char 指針,將您的指針向前增加 x 個字節。

C 標准不允許指針算術。 但是,考慮到void的大小為1GNU C是允許的。

C11 標准 §6.2.5

第 19 段

void類型包含一組空值; 它是無法完成的不完整對象類型

以下程序在 GCC 編譯器中運行良好。

#include<stdio.h>

int main()
{
    int arr[2] = {1, 2};
    void *ptr = &arr;
    ptr = ptr + sizeof(int);
    printf("%d\n", *(int *)ptr);
    return 0;
}

可能是其他編譯器產生錯誤。

您不能對void *類型進行指針運算,正是出於這個原因!

在進行指針運算之前,您必須將其轉換為另一種類型的指針。

空指針可以指向任何內存塊。 因此,當我們嘗試對 void 指針進行指針算術時,編譯器不知道要增加/減少多少字節。 因此,void 指針必須首先被類型轉換為已知類型,然后才能參與任何指針運算。

void *p = malloc(sizeof(char)*10);
p++; //compiler does how many where to pint the pointer after this increment operation

char * c = (char *)p;
c++;  // compiler will increment the c by 1, since size of char is 1 byte.

void 指針中不允許進行指針運算。

原因:指針算術與普通算術不同,因為它是相對於基址發生的

解決方案:在算術時使用類型轉換運算符,這將使執行指針算術的表達式的基本數據類型已知。 例如:point 是空指針

*point=*point +1; //Not valid
*(int *)point= *(int *)point +1; //valid

編譯器通過類型轉換知道。 給定一個void *x

  • x+1x增加一個字節,指針指向字節x+1
  • (int*)x+1添加sizeof(int)個字節,指針指向字節x + sizeof(int)
  • (float*)x+1地址sizeof(float)字節等。

盡管第一項是不可移植的,並且與 C/C++ 的 Galateo 背道而馳,但它仍然是 C 語言正確的,這意味着它可以在大多數編譯器上編譯為某些內容,可能需要一個適當的標志(如 -Wpointer-arith)

暫無
暫無

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

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