sirven que punteros puntero para operaciones los declaracion con arreglos aritmetica apuntadores c pointers void-pointers pointer-arithmetic

que - Aritmética de puntero para el puntero de vacío en C



punteros en c (8)

¡No se puede hacer una aritmética de punteros en los tipos void * , exactamente por esta razón!

Cuando se incrementa un puntero a un tipo particular (digamos int , char , float , ..), su valor aumenta por el tamaño de ese tipo de datos. Si se incrementa un puntero de void que apunta a datos de tamaño x , ¿cómo llega a apuntar x bytes adelante? ¿Cómo sabe el compilador agregar x al valor del puntero?


Conclusión final: la aritmética en un void* es ilegal tanto en C como en C ++.

GCC lo permite como una extensión, consulte Aritmética en void - y Punteros de función (tenga en cuenta que esta sección es parte del capítulo "Extensiones C" del manual). Clang e ICC probablemente permitan la aritmética void* con fines de compatibilidad con GCC. Otros compiladores (como MSVC) no permiten la aritmética en void* , y GCC la deshabilita si se especifica el -pedantic-errors , o si se especifica el -Werror-pointer-arith (este indicador es útil si su base de código también debe compilar con MSVC).

El estándar C habla

Las citas se toman del borrador n1256.

La descripción de la norma de la operación de adición indica:

6.5.6-2: para la suma, ambos operandos deben tener un tipo aritmético, o un operando debe ser un puntero a un tipo de objeto y el otro debe tener un tipo entero.

Entonces, la pregunta aquí es si void* es un puntero a un "tipo de objeto", o lo que es lo mismo, si void es un "tipo de objeto". La definición para "tipo de objeto" es:

6.2.5.1: Los tipos se dividen en tipos de objetos (tipos que describen completamente los objetos), tipos de funciones (tipos que describen funciones) y tipos incompletos (tipos que describen objetos pero carecen de la información necesaria para determinar sus tamaños).

Y el estándar define el void como:

6.2.5-19: el tipo de void comprende un conjunto vacío de valores; es un tipo incompleto que no puede completarse.

Como el void es un tipo incompleto, no es un tipo de objeto. Por lo tanto, no es un operando válido para una operación de suma.

Por lo tanto, no puede realizar aritmética de puntero en un puntero de void .

Notas

Originalmente, se pensó que se permitía la aritmética void* debido a estas secciones del estándar C:

6.2.5-27: Un puntero a vacío tendrá los mismos requisitos de representación y alineación que un puntero a un tipo de carácter.

Sin embargo,

Los mismos requisitos de representación y alineación implican intercambiabilidad como argumentos para funciones, valores de retorno de funciones y miembros de uniones.

Esto significa que printf("%s", x) tiene el mismo significado si x tiene tipo char* o void* , pero eso no significa que se pueda hacer aritmética en un void* .

Nota del editor: esta respuesta ha sido editada para reflejar la conclusión final.


El estándar C no permite la aritmética del puntero nulo . Sin embargo, GNU C está permitido al considerar que el tamaño del vacío es 1 .

C11 estándar §6.2.5

Párrafo - 19

El tipo de void comprende un conjunto vacío de valores; es un tipo de objeto incompleto que no se puede completar.

El siguiente programa funciona bien en el compilador de 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; }

Puede ser que otros compiladores generen un error.


El compilador sabe por tipo de molde. Dado un void *x :

  • x+1 agrega un byte a x , el puntero va al byte x+1
  • (int*)x+1 agrega sizeof(int) bytes, el puntero va al byte x + sizeof(int)
  • (float*)x+1 addres sizeof(float) bytes, etc.

Aunque el primer elemento no es portátil y está en contra del Galateo de C / C ++, sin embargo es C-language-correct, lo que significa que compilará algo en la mayoría de compiladores que posiblemente necesite una bandera apropiada (como -Wpointer-arith)


La aritmética del puntero no está permitida en los punteros void* .


Los punteros vacíos pueden señalar cualquier fragmento de memoria. Por lo tanto, el compilador no sabe cuántos bytes incrementar / disminuir cuando intentamos la aritmética del puntero en un puntero void. Por lo tanto, los punteros vacíos deben ser primero encasillados a un tipo conocido antes de que puedan estar involucrados en cualquier aritmética del puntero.

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.


Tienes que convertirlo en otro tipo de puntero antes de realizar la aritmética del puntero.


lanzarlo a un puntero char e incrementar su puntero hacia adelante x bytes adelante.