fredericopissarra Postado Março 24, 2019 em 04:02 Compartilhar Postado Março 24, 2019 em 04:02 Existe uma diferença entre declarar e usar algo numa expressão. Por exemplo, a declaração: char s[] = "fred"; Define um array s que será preenchido com 5 caracteres (o '\0' também conta), mas esses 5 caracteres não serão alocados numa sessão read-only da imagem binária (dado o literal "fred", acima). Mas, usar uma "string" literal numa expressão, ou chamada de função, pode forçar o compilador a criar um array "read-only": if ( ! strcmp ( s, "fred" ) ) do_something(); Neste caso os 5 bytes de "fred" serão colocados na sessão .rodata, obrigatoriamente, porque a função strcmp() exige o uso de um ponteiro. O mesmo acontece com a declaração: char *s = "fred"; Sabendo que esse literal entre aspas é um atalho para uma sequência de bytes (um array), podemos comparar duas "strings" com até 8 chars (contando o '\0' final), assim [compare as funções f() e g()]: #include <string.h> int f( char *s ) { return ! strcmp( s, "fred" ); } int g( char *s ) { long long a, b; a = *(long long *)s; b = *(long long *)"fred"; return ( ( a & 0xffffffffffULL ) - b ) == 0; } A função f() é esquisita. Repare como usei o literal "fred" como ponteiro long long e o dereferenciei... Outra coisa é que tive que mascarar os bits superiores de a, a partir do 6º byte porque, na comparação, o 5º byte precisa ser 0. f() parece mais complicada e, portanto, supostamente, o código fica mais lento, certo? Errado: Essa assertiva quase nunca é verdadeira. O tamanho e performance do código depende do que ele faz, não da quantidade de linhas e expressões que ele contém. Eis a listagem em assembly das duas rotinas: section .rodata ro_fredstr: db 'f', 'r', 'e', 'd', 0, 0, 0, 0 section .text f: mov rsi,rdi lea rdi,[ro_fredstr] mov ecx,5 rep cmpsb seta al sbb al,0 test al,al sete al movzx eax,al ret g: mov rax,0xffffffffff and rax,[rdi] cmp rax,[ro_fredstr] sete al movzx eax,al ret Claro, isso só funciona com comparações com strings de até 8 caracteres e com tamanho previamente conhecido (temos que criar a máscara de acordo!). Não é lá muito "usável" no dia-a-dia, mas ilustra o ponto de que podemos criar rotinas mais rápidas usando esse tipo de macete. Outro detalhe interessante sobre strings literais em expressões: Como elas podem ser alocadas como arrays e a especificação nos diz, explicitamente, que o operador [] é um atalho para uma expressão usando ponteiros, isto é: c = a[i]; // isto é a mesma coisa que... c = *(a+i); // ... isto! Podemos escrever, sem problemas, algo assim: c = "fred"[2]; // c será 'e'. E como qualquer adição segue a propriedade comutativa (a+b = b+a), uma construção, válida, mas até mais estranha, é possível: c = 2["fred"]; Interessante, não? Link para o comentário Compartilhar em outros sites More sharing options...
Aof Postado Março 25, 2019 em 16:49 Compartilhar Postado Março 25, 2019 em 16:49 a = *(long long *)s; b = *(long long *)"fred"; so nao entedi essa parte. sei que o "*" antes do "(" significa que e um ponteiro, mas "long long *" complicou. aof abc. Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Março 25, 2019 em 17:33 Autor Compartilhar Postado Março 25, 2019 em 17:33 44 minutos atrás, Aof disse: a = *(long long *)s; b = *(long long *)"fred"; so nao entedi essa parte. sei que o "*" antes do "(" significa que e um ponteiro, mas "long long *" complicou. Nope... o * antes de (long long *) é um operador de indireção... ele pega o valor inteiro na variável ponteiro e o usa para obter o dado para onde esse endereço aponta. O (long long *) é um operador de casting (conversão) que, neste caso, converte o ponteiro do tipo char * para o tipo long long *. Assim, o operador * será obrigado a acessar 8 bytes (de um long long), não apenas 1 (de um char). Link para o comentário Compartilhar em outros sites More sharing options...
Posts Recomendados
Arquivado
Este tópico foi arquivado e está fechado para novas respostas.