Pregunta

Estoy escribiendo una función de acceso que devuelve un puntero a un buffer interno y me gustaría hacer alusión a los usuarios de mi función que no deben actualizar el objeto al apuntado. Un ejemplo muy artificial sería:

void myAccessFunc(bool string, void* p, size_t* len)
{
  static const char* s = "aha!";
  static const int i = 123;

  if (string) {
     *(char**)p = &s;
     *len = strlen(s);
  }
  else {
     *(int**)p = &i;
     *len = sizeof(i);
  }
}

char* s;
size_t bytes;
myAccessFunc(true,&s, &bytes);
printf("Got '%s'\n", s);

Sí, ya sé que se ve raro.

Lo que quiero evitar es:

char* s;
size_t bytes;
myAccessFunc(true,&s,&bytes);
s[4] = '?';

Yo sé que no puedo evitar por completo, pero me gustaría al menos igual que la advertencia del compilador hacer alusión a un usuario que no deberían estar haciendo eso. Si echaron mi puntero, entonces ese es su problema. ¿Hay alguna combinación de const * y sin efecto y que lo hará? He intentado algo como:

void myAccessFunc(bool string, const void** p, size_t* len);

pero parecía acabar con el vacío del puntero de modo que una persona que llama tenía que ver:

const void* p;
size_t bytes;
myAccessFunc(true, &p, &bytes);

o

const char* s;
size_t bytes;
myAccessFunc(true, (const void**)&s, &bytes);

y no podía hacer:

const int * ip;
const char* s;
size_t bytes;
myAccessFunc(true, &s, &bytes);
myAccessFunc(false, &i, &bytes);

finalmente llegué en torno a:

const void* myAccessFunc(bool string, size_t* len);

y si el usuario hace:

char* p = myAcccessFunc(true,&bytes);

el compilador (GCC, por lo menos), no se quejan de tirar el calificador.

¿Fue útil?

Solución

Lo mejor sería hacer algo como:

const void * myAccessFunc();

Cuando regrese el puntero a la zona interna, esto es un poco más natural que pasa como un parámetro de salida.

Si se va a pasarlo como un parámetro de salida, usted quiere:

void myAccessFunc(const void **p);

lo que les impide hacer esto por accidente:

void *p;  /* error: must be 'const void *p;' */
myAccessFunc(&p);

Otros consejos

Hay dos cosas que puede hacer:

  • Devuelve una const void *
  • Escriba alguna documentación de la API diciendo a los usuarios a no modificar el valor devuelto

Dicho esto, cualquier usuario de la API que decide tratar de lodo con un puntero al igual que merece lo que reciben:. P

La prevención es imposible, ya que se puede desechar constness. Si usted hace su const parámetro de función, que tendrá que derribó a sí mismo dentro de la función. También estaría mintiendo a cualquier persona que utilice su función y podría causar todo tipo de insectos divertidas.

Usted podría intentar devolver un puntero en su lugar. A continuación, al menos no estaría violando su propio const. Eso puede no ser apropiado en este caso, sin embargo.

Volviendo un puntero sería mejor, pero si absolutamente necesita para que sea un parámetro de salida, se puede usar una estructura como intermediario:

typedef struct _ptr_holder {
   const void* ptr;
} ptr_holder;

void myAccessFunc( bool string, ptr_holder* ptr ) {
...
}

ptr_holder s;
myAccessFunc(true,&s);
printf("Got '%s'\n", s.ptr);

Es mal, pero se debe hacer el truco

Así que usted quiere evitar la modificación de la vía el puntero a la vuelta? Prueba esto:

const void* myAccessFunc(bool string);

¿Qué hay de malo en esto? Si usted va a votar en contra de una respuesta válida, por favor dejar un comentario.

Si usted está escribiendo una biblioteca de C en el que no desea exponer algunos-estructura de datos interna que puede ser bueno para ir de un ruta adicional y ocultar la aplicación con un typedef struct no especificado. Esto también se llama un tipos opacos

Ejemplo:

En my_interface.h

 #ifndef __MYINTERFACE_H__
 #define __MYINTERFACE_H__

 /* The unspecified struct statement */
 typedef struct s_my_data t_my_data;

 t_my_data  *new_my_data(int someInitializer);
 void        free_my_data(t_my_data *data);
 int         enter_my_data(t_my_data *data, int someDataToEnter);

 const char *return_str_my_data(t_my_data *data);

 #endif /* __MYINTERFACE_H__ */



En my_interface.c

 #include <my_interface.h>

 /* Keep struct in .c file */
 struct s_my_data {
     int    length;
     char  *string;
 };

 t_my_data *new_my_data(int someInitializer)
 {
     /* the exercise */
 }

 void free_my_data(t_my_data *data)
 {
     /* the exercise */
 }

 int enter_my_data(t_my_data *data, int someDataToEnter)
 {
     /* the exercise */
 }

 const char *return_str_my_data(t_my_data *data)
 {
     /* the exercise */
 }

Es esto C o C ++? ¿Por qué en el caso int estás pasando el puntero a una constante estática? La interfaz es sospechoso.

sobrecarga y deshacerse del booleano en la interfaz:

void myAccessFunc( const char* * const p, size_t* len){
   *p = "blahblahblah";
   *len = 12;
}

void myAccessFunc( const int* * const ppI, size_t* len){
   static const int i = 123;
   *ppI = &i;
   *len = 4;
}

Se deshace de la prueba también. Dado que el usuario conoce la verdadera o falsa de la función original que sabe cuál utilizar. tipificación fuerte es su amigo. Se deshace de la clase de errores donde el tipo y el puntero sean incompatibles ...

pasando BTW tales indicadores de control frente a la sobrecarga no es deseable, especialmente en métodos pequeñas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top