Pergunta

Eu estou escrevendo uma função de acesso que retorna um ponteiro para um buffer interno e eu gostaria de sugerir aos usuários da minha função que eles não devem atualizar o objeto que está apontado. Um exemplo muito artificial seria:

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);

Sim, eu sei que a aparência flakey.

O que quer evitar é:

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

Eu sei que não pode impedi-lo completamente, mas eu, pelo menos, como o aviso do compilador a dica para um usuário que não deveria estar fazendo isso. Se eles lançam meu ponteiro, então isso é problema deles. Existe alguma combinação de const e sem efeito e * que vai fazer isso? Eu tentei algo como:

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

mas parecia acabar com o vazio do ponteiro assim um chamador tinha que fazer:

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

ou

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

e não poderia fazer:

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

Eu finalmente veio em torno de:

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

e se o usuário faz:

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

o compilador (GCC, pelo menos), se queixa jogando fora o qualificador.

Foi útil?

Solução

Seria melhor para fazer algo como:

const void * myAccessFunc();

Onde você retornar o ponteiro para os internos, isto é um pouco mais natural do que passá-lo como um parâmetro de saída.

Se você tivesse que passá-lo como um parâmetro de saída, você iria querer:

void myAccessFunc(const void **p);

que os impede de fazer isso acidentalmente:

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

Outras dicas

Você tem duas coisas que você pode fazer:

  • Voltar a const void *
  • Escrever alguma documentação para o seu API dizendo aos usuários em não modificar o valor retornado

Com isso dito, qualquer usuário API que decide tentar e muck com um ponteiro assim merece o que recebem:. P

A prevenção é impossível, desde que você pode jogar fora constness. Se você fazer o seu parâmetro de função const, você vai ter que lançou por terra a si mesmo dentro da função. Você também estaria mentindo para qualquer pessoa usando a sua função e pode causar todos os tipos de insetos divertidos.

Você poderia tentar retornar um ponteiro em vez. Então você pelo menos não estar violando sua própria const. Isso pode não ser apropriado neste caso, no entanto.

Retornando um ponteiro seria melhor, mas se você absolutamente necessidade de torná-lo um parâmetro de saída, você poderia usar um struct como um intermediário:

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);

É de piegas, mas deve fazer o truque

Assim que você quer impedir a modificação da via o ponteiro você voltar? Tente isto:

const void* myAccessFunc(bool string);

O que está errado com isso? Se você estiver indo para voto por uma resposta válida, por favor deixe um comentário.

Se você estiver escrevendo uma biblioteca C, onde você não deseja expor algumas-estrutura de dados interna que pode ser bom para ir um extra route e se esconder implementação com um typedef struct não especificado. Isto também é chamado um opacos tipos

Exemplo:

Em 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__ */



Em 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 */
 }

É este o C ou C ++? Por que no caso int que você está passando o ponteiro para uma const estático? A interface é suspeito.

Overload e se livrar do boolean na interface:

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 livrar do teste também. Uma vez que o usuário sabe verdadeiro ou falso para a função original ele sabe qual usar. tipagem forte é seu amigo. Se livrar da classe de erros, onde tipo e ponteiro são inconsistentes ...

Entre passando tais bandeiras de controlo contra sobrecarga é indesejável, especialmente assim em pequenas métodos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top