Strings: A diferença entre ponteiros e arrays

Eu sei… eu sei… já falei disso em outro post. Só quero provar o meu ponto.

Eu disse que as duas declarações abaixo são muito parecidas, mas bem diferentes do ponto de vista do código gerado…. Isso é especialmente verdade se elas forem declaradas dentro de uma função:

char s[] = "a";
char *s = "a";

Para provar isso vou mostrar duas funçõeszinhas bem simples e gerar a listagem em assembly do código otimizado:

/* test.c */

/* Só o protótipo aqui */
void printstr(char *);

void f(void)
{
  char s[] = "a";
  printstr(s);
}

void g(void)
{
  char *s = "a";
  printstr(s);
}

Compilando e vendo o código que o compilador gerou:

$ gcc -mtune=native -O3 -fomit-frame-pointer -masm=intel -S test.c
$ cat test.s
/* Tirei um monte de definições daqui, ok? */
.LC0:
  .string "a"

f:
  sub   esp, 44
  movzx eax, WORD PTR .LC0
  mov   WORD PTR [esp+30], ax
  lea   eax, [esp+30]
  mov   DWORD PTR [esp], eax
  call  printstr
  add   esp, 44
  ret

g:
  sub   esp, 28
  mov   DWORD PTR [esp], OFFSET FLAT:.LC0
  call  printstr
  add   esp, 28
  ret

A função g() simplesmente pega o endereço da constante .LC0 e repassa para printstr(). Enquanto a função f() copia a constante para a pilha, pega o endereço da pilha e passa para a função printstr(). Ou seja, a função f() usa 3 instruções adicionais somente para inicializar o vetor. Isso porque temos um vetor de apenas 2 posições (o ‘a’ e o (char)0). Se a string fosse algo como “usar vetores pode ser uma coisa bem lenta e gerar um código grandão pra caramba”, então o código de g() seria exatamente o mesmo que esse ai em cima, mas a função f() teria várias instruções “mov” ou um loop para inicializar o vetor e somente depois disso passar o ponteiro para printstr().

Regra geral: Evite usar vetores!

Anúncios

6 comentários sobre “Strings: A diferença entre ponteiros e arrays

  1. Dê uma olhada no livro do Peter Van Linden – Expert C Programming Deep C Secrets.
    Na ocasião em que li entendi, sem ter que ir fundo nos asm da vida.

    Chapter 4. The Shocking Truth: C Arrays and Pointers Are NOT the Same!

    extern int *x;
    extern int y[];

    The first declares x to be a pointer to int; the second declares y to be an array of int of
    unspecified size (an incomplete type), the storage for which is defined elsewhere.

    Dai ele segue com o sutil ponto de diferença entre definição e declaração

    What’s a Declaration? What’s a Definition?
    definition occurs in only one place specifies the type of an object; reserves storage for it; is used to create new objects
    example: int my_array[100];

    declaration can occur multiple describes the type of an object; is used to refer to objects defined times elsewhere (e.g., in another file)
    example: extern int my_array[];

    O que então dá a tônica… Um ponteiro pode vir a ser um array, enquanto o array já é uma posição, ocorre que ambas as variáveis contém endereços, uma para uma área que está ou não alocada e outra, o array, pressupõe-se que esteja alocada.

    E se fossem iguais, você poderia atribuir um r-value para o array.


    cat -n main.c -n
    1 #include
    2
    3 int main(void)
    4 {
    5 int a[1] = 1;
    6 int *b;
    7
    8 b = a;
    9 a = b;
    10 }

    $ make main
    cc main.c -o main
    main.c: In function ‘main’:
    main.c:5: error: invalid initializer
    main.c:9: error: incompatible types when assigning to type ‘int[1]’ from type ‘int *’
    make: ** [main] Erro 1

      1. Thx, pela correção.
        Kibei alguns trechos do livro e não atentei para o detalhe da inicialização do array no exemplo que bolei e nem a do vetor, mas a idéia central que quis passar no comentário foi de que para provar o ponto, um exemplo mais palatável, que asm seria suficiente. IMHO é claro.

      2. Hehehe… como te falei por e-mail, essa “correção” foi exagero da minha parte. O seu ponto foi corretamente apontado no comentário… a inicialização errada do array é apenas um detalhe bobo…

        O que einha achado estranho, numa primeira olhada, eram as atribuições dos “ponteiros” ‘a’ e ‘b’, mas estavam totalmente coerentes com o seu argumento (que tb está no meu post anterior – disfarçado.. hehe).

        Anyway… por isso eu deletei minha resposta ao comentário e, como somos autores, você foi capaz de vê-lo tb… sorry.

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s