Nos meus programas em C, muitas vezes preciso de uma maneira de fazer uma representação em string dos meus ADTs. Mesmo que eu não precise imprimir a string para a tela de alguma forma, é interessante ter esse método para depuração. Portanto, esse tipo de função geralmente surge.
char * mytype_to_string( const mytype_t *t );
Realmente percebo que tenho (pelo menos) três opções aqui para manipular a memória para a sequência retornar.
Alternativa 1: Armazenando a sequência de retorno em uma matriz estática de caracteres na função Não preciso pensar muito, exceto que a corda é substituída a cada chamada. O que pode ser um problema em algumas ocasiões.
Alternativa 2: aloque a string na pilha com malloc dentro da função. Muito legal, pois não precisarei pensar no tamanho de um buffer ou na substituição. No entanto, eu tenho que lembrar de liberar () a string quando terminar, e também preciso atribuir a uma variável temporária para que eu possa liberar. e, em seguida, a alocação de heap é realmente muito mais lenta que a alocação de pilha; portanto, haverá um gargalo se isso for repetido em um loop.
Alternativa 3: Passe o ponteiro para um buffer e deixe o chamador alocar esse buffer. Gostar:
char * mytype_to_string( const mytype_t *mt, char *buf, size_t buflen );
Isso traz mais esforço para o chamador. Percebo também que essa alternativa me dá uma outra opção na ordem dos argumentos. Qual argumento devo ter primeiro e último? (na verdade seis possibilidades)
Então, qual devo preferir? Algum porque? Existe algum tipo de padrão não escrito entre os desenvolvedores C?
fonte
sysctlbyname
no OS X e iOSRespostas:
Os métodos que eu mais vi são 2 e 3.
O buffer fornecido pelo usuário é realmente bastante simples de usar:
Embora a maioria das implementações retorne a quantidade de buffer usada.
A opção 2 será mais lenta e é perigosa ao usar bibliotecas vinculadas dinamicamente, onde eles podem usar tempos de execução diferentes (e pilhas diferentes). Portanto, você não pode liberar o que foi alocado em outra biblioteca. Isso requer uma
free_string(char*)
função para lidar com isso.fonte
printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));
e, portanto, não gostaria de retornar o comprimento usado, mas o ponteiro para a string. O comentário da biblioteca dinâmica é realmente importante.sizeof(buffer) - 1
para satisfazer o\0
terminador?snprintf
uso.Ideia de design adicional para # 3
Quando possível, forneça também o tamanho máximo necessário para
mytype
o mesmo arquivo .h quemytype_to_string()
.Agora o usuário pode codificar adequadamente.
Ordem
O tamanho das matrizes, quando primeiro, permite tipos de VLA.
Não é tão importante com uma dimensão única, mas útil com 2 ou mais.
Lembro-me de que a leitura do tamanho primeiro é o idioma preferido no próximo C. Precisa encontrar essa referência ...
fonte
Como complemento à excelente resposta de @ ratchetfreak, eu indicaria que a alternativa nº 3 segue um paradigma / padrão semelhante ao das funções padrão da biblioteca C.
Por exemplo
strncpy
,.Seguir o mesmo paradigma ajudaria a reduzir a carga cognitiva dos novos desenvolvedores (ou mesmo do seu futuro) quando eles precisarem usar sua função.
A única diferença com o que você tem em sua postagem seria que o
destination
argumento nas bibliotecas C tende a ser listado primeiro na lista de argumentos. Então:fonte
Além do fato de que você está propondo fazer um mau cheiro de código, a alternativa 3 me parece melhor. Também acho que @ gnasher729 você está usando a linguagem errada.
fonte
Para ser sincero, convém mudar para um idioma diferente, no qual retornar uma string não é uma operação complexa, trabalhosa e propensa a erros.
Você pode considerar C ++ ou Objective-C, onde pode deixar 99% do seu código inalterado.
fonte