Um recurso bastante útil do GCC (apenas) são vetores de tamanho zero. O uso é permitido apenas como último elemento de uma estrutura de dados.
struct pessoa { int idade; char nome[0]; };
printf("%d\n", sizeof(struct pessoa)); // Imprime "4"
Note que a estrutura tem o mesmo tamanho de um inteiro (na minha máquina). Então podemos concluir que o vetor de tamanho zero não ocupa espaço, ele apenas serve como um identificador para a primeira posição de memória após a estrutura. Isto nos permite fazer algo assim:
struct pessoa * cria_pessoa(int idade, char* nome) { int tamanho = sizeof(struct pessoa) + strlen(nome) + 1; struct pessoa *novo = malloc(tamanho); novo->idade = idade; strcpy(novo->nome, nome); return novo; }
int main(void) { struct pessoa *teste = cria_pessoa(18, "Jose"); /* Imprime "Jose tem 18 anos." */ printf("%s tem %d anos.\n", teste->nome, teste->idade); free(teste); return 0; }
Note que conseguimos alocar toda a memória para a estrutura em apenas uma operação, o que não seria possível caso “nome” fosse um ponteiro, o que nos custaria mais uma chamada de malloc. Da mesma forma a desalocação de toda a estrutura foi feita usando um comando.
Esta técnica permite maior flexibilidade e um melhor aproveitamento de memória do que construir a estrutura com o atributo nome sendo “char nome[200]” (tamanho fixo) supondo que um nome nunca seria maior que 200 caracteres.
Funciona por causa do compilador.
struct pessoa * cria_pessoa(int idade, char* nome)
{
…
strcpy(novo->nome, nome); /* aqui deveria dar segfault */
…
}
Compilando no gcc 4.0.1 no macbook sem usar flags, passa. Mas com -pedantic gera warning:
vet0.c:7: warning: ISO C forbids zero-size array ‘nome’
Sim, é uma extensão do GCC apenas, como disse na dica. Quem quiser fazer um código portável entre compiladores vai ter que viver sem essa. :)
Oooopss… my bad
C99 suporta “flexible arrays”. Referência: http://publib.boulder.ibm.com/infocenter/comphelp/v9v111/index.jsp?topic=/com.ibm.xlcpp9.aix.doc/language_ref/strct.htm
Ver ali “Flexible array members” e “Zero-extent array members”. Especificamente:
“””…
Zero-extent array members
A zero-extent array is an array with no dimensions. Like a flexible array member, a zero-extent array can be used to access a variable-length object. Unlike a flexible array member, a zero-extent array is not a C99 feature, but is provided for GNU C compatibility.
…”””
;]
Pra mim essa é nova…
Gostei da idéia!
Vou testar algumas coisinhas!
Se não me engano, o Codewarrior suporta isso também. Uma forma portável de fazer isso é declarando o array no fim da struct como tendo um elemento.
Supondo que a struct seja do tipo S, e o array do tipo T (e o queremos com n elementos), é só alocar usando malloc(sizeof(S) + (n – 1) * sizeof(T))
Boa dica! e a do zpu k também!