You are currently browsing Alfredo Kojima's articles.
Se sua pressão aumenta toda vez que vê essa mensage no Visual Studio, é possível desabilitar totalmente essa funcionalidade:
Vá em: C:\Program Files\Microsoft Visual Studio 8\VC\vcpackages ou equivalente na sua máquina e apague (ou renomeie para algo inócuo) o arquivo feacp.dll.
Isto desabilita o Intellisense para C++, mas não para C# (onde ele funciona melhor). Infelizmente isto também desabilita funcionalidades como o auto-complete ou a navegação “inteligente” entre arquivos.
É, pode ser um preço pequeno a pagar pela manutenção de sua sanidade.
Apesar dos templates para hash_set e hash_map não serem padronizados, ambos são relativamente comuns, estando disponíveis tanto na implementação GNU (ie, no GCC) quanto no Visual C++ no Windows. Existem algumas diferenças, como o namespace um pouco mais escondido no GNUC (__gnu_cxx vs stdext) e alguns métodos que existem em um mas não em outro (p.ex.: reverse_iterator que não existe no GCC); mas a maioria das vezes servem para o serviço.
Um problema comum com essas classes no GCC é um erro meio criptico quando tentamos usar __gnu_cxx::hash_set<std::string> ou __gnu_cxx::hash_map<std::string>:
/usr/include/c++/4.2/ext/hashtable.h:595: error: no match for call to '(const __gnu_cxx::hash<std::basic_string<char, std::char_traits, std::allocator > >) (const std::basic_string<char, std::char_traits, std::allocator >&)'
Este erro ocorre porque a libstdc++ não define uma função de hash para std::string. A solução é definir uma (O RLY?). Felizmente a biblioteca padrão define uma função de hash para strings do tipo char*, então podemos aproveitá-la:
struct string_hash : public std::unary_function<std::string,size_t>
{
size_t operator() (const std::string &v) const
{
return __gnu_cxx::hash()(v.c_str());
}
};
typedef __gnu_cxx::hash_set<std::string,string_hash> string_hash_set;
Para obter ponteiros a métodos ou funções sobrecarregadas, como exemplo:
class Foo
{
public:
void bla(int a);
int bla() const;
};
Se tentarmos usar o nome da função diretamente, o compilador não saberá a qual dos métodos você se refere. Para sair da ambiguidade, necessitamos usar a “assinatura” (os tipos dos parâmetros e do valor retornado) da função indiretamente, possivelmente com o uso de variáveis temporárias:
void (Foo::*ptr1)(int)= &Foo::bla; int (Foo::*ptr2)() const= &Foo::bla;
Palavras-chave: C, C++, varargs, argumentos variáveis
Para escrever funções que aceitam quantidade variável de parâmetros, usa-se o mecanismo de stdargs do C. Para isso coloca-se “…” como último parâmetro na declaração da função e depois usa-se as funções de stdarg.h para acessar os valores passados quando a funcão é chamada.
-
É obrigatório a inclusão de pelo menos um parâmetro normal antes da parte variável. (ex.:
char *concat(const char *s, ...)) -
Qualquer tipo de valor pode ser passado como parâmetro, mas é impossível determinar em runtime o tipo dos valores que uma função recebeu. Porém é possível criar formas de o código que chama a funcão comunicar os tipos dos valores passados. Por exemplo, a função printf() determina os tipos dos parâmetros recebidos pela string de formatação (%s para char*, %i para int etc); a função
concat()no exemplo espera que todos os parâmetros recebidos sejam strings e assim por diante. -
O número de parâmetros recebido também não pode ser determinado explicitamente. É necessário usar artifícios adicionais como passar uma variável extra com o número de valores sendo passados, usar o valor NULL como indicador de último parâmetro ou derivar a quantidade de valores a partir da string de formatação, como no caso do printf() e similares.
Exemplo:
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, ...)
{
va_list args;
char *tmp;
char *res;
size_t len= strlen(s);
// pega um handle ao início da lista de parâmetros
va_start(args, s);
// calcula o tamanho total de todas as strings
// pega o próximo parâmetro da lista, até chegar no NULL
while ((tmp= va_arg(args, char*))) {
len+= strlen(tmp);
}
va_end(args);
res= malloc(len+1);
if (!res) return NULL;
// cria a string concatenada
strcpy(res, s);
va_start(args, s);
// pega o próximo parâmetro da lista, até chegar no NULL
while ((tmp= va_arg(args, char*))) {
strcat(res, tmp);
}
va_end(args);
return res;
}
int main()
{
char *s= concat("hello", " ", "world", "!!!!", NULL);
puts(s);
free(s);
return 0;
}
Se você quer usar macros com número de parâmetros variável (por exemplo, uma macro que chama uma função com stdargs), veja o post sobre o assunto.
Palavras-chave: C++, C, C#, precompiled header, prefix header, g++, lento
Se seu programa em C++ demora séculos para compilar, considere usar um recurso do GCC 4 que acelera compilações de maneira bastante simples.
Um dos motivo porque programas C++ demoram tanto para compilar é a grande quantidade de headers a se incluir. Um programa com #include <gtkmm.h>, por exemplo, vai incluir literalmente milhares de arquivos, dentre eles os do gtkmm em si, glibmm, pangomm, atkmm, sigc++, gtk+, pango, atk, gdk, glib etc etc etc. Além disso, pela complexidade de linguagem, o processamento de headers C++ é demorado.
Como isso tudo é feito para cada arquivo fonte do programa, no final das contas é bem possível que boa parte do tempo de compilação seja gasto processando esse mesmo grupo de headers tantas vezes quanto o número de arquivos no seu projeto.
No GCC 4 foi incluído o recurso de pré-compilação de headers. Ou seja, você pode pré-compilar os headers em separado para que este passo não precise ser repetido para cada arquivo. Para pré-compilar um cabeçalho, simplesmente rode o gcc nele como se fosse compilar um arquivo fonte comum:
% g++ meuheader.h -I/path/para/diretorios/de/includes (se tudo der certo, um arquivo meuheader.h.gch será gerado)
Se o gcc encontrar a versão pré-compilada de um header enquanto procura por ele, esta será usada. Uma forma simples de se usar esse recurso no seu projeto é pré-compilar um “prefix header” que será automaticamente incluído no começo de todos os arquivos fonte de seu programa. Este arquivo deve conter #includes para todos os headers que seu programa precisa.
Segue uma receita de bolo para usar prefix headers pré-compilados:
- Crie um arquivo (por exemplo, prefix_header.h) que inclua todos os headers de bibliotecas que seu programa usa, ex.:
#include <list> #include <vector> #include <string> #include <map> #include <gtkmm.h> #include <cairo.h> #include <math.h>
- Compile prefix_header.h
% g++ prefix_header.h $(pkg-config gtkmm-2.4 cairo --cflags)
- Compile seu programa usando o prefix header
% make "CXXFLAGS=-include prefix_header.h"
Isso também funciona em C e Objective-C, mas a maior diferença pode ser notada no C++.
Palavras-chave: C, arquivo texto, linhas, leitura, getline
Como dito num post anterior, a glibc possui uma função para ler linhas de comprimento arbitrário de um arquivo texto. Mas como esta função é especifica a glibc, alguns leitores pediram uma versão que faça o mesmo em qualquer sistema. Uma das muitas formas de fazer isto é:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *pegalinha(FILE *f, char **buffer, size_t *buflen)
{
char *ptr;
char *tmp;
int c;
if (!*buffer || !*buflen)
{
*buflen= 32;
*buffer= (char*)malloc(*buflen);
if (!*buffer)
return NULL;
}
ptr= *buffer;
while ((c= fgetc(f)) != EOF) {
*ptr++= c;
if (c == '\\n') break;
if (ptr - *buffer >= *buflen-1)
{
// aumenta o buffer um pouco mais
tmp= (char*)realloc(*buffer, *buflen+32);
if (!tmp)
return NULL;
// atualiza ptr para o caso do novo buffer estar em outro lugar
ptr= tmp + (ptr - *buffer);
*buflen+= 32;
*buffer= tmp;
}
}
*ptr= 0;
return c==EOF ? NULL : *buffer;
}
int main(int argc, char **argv)
{
FILE *file;
char *linha= NULL;
size_t tamlinha= 0;
if (argc != 2) { printf("%s \\n", argv[0]); exit(1); }
if (!(file= fopen(argv[1], "r"))) { perror(argv[1]); exit(1); }
while (pegalinha(file, &linha, &tamlinha))
{
printf("%i:%s", tamlinha, linha);
}
if (linha)
free(linha);
fclose(file);
return 0;
}
Palavras-chave: Python, split, tokenizacão, análise léxica, parser, strings, quotes, aspas
O módulo re possui a conveniente função split(), que faz o mesmo que o split() dos strings, mas aceita expressões regulares como separador. Isto pode ser aproveitado para fazer um “parser de pobre” para casos simples, como por exemplo, quebrar um texto em palavras, levando em conta “strings” entre aspas:
>>> texto="lorem ipsum dolor 'hello world' 'mais texto'' assim'"
>>> print filter(None,re.split("('(?:[^']|'')*')| ", texto))
['lorem', 'ipsum', 'dolor', "'hello world'", "'mais texto'' assim'"]
O filter() é necessário para remover espaços em branco e Nones que sobram no resultado. Como bônus, strings podem conter ' escapados com ''.
Palavras-chave: Unicode, utf8, SQLObject, TurboGears, erro
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 50: ordinal not in range(128)
Este erro pode ocorrer quando se tenta executar queries que envolvem caracteres Unicode (na query em si ou no resultado) usando SQLObject (o módulo de banco de dados usado no TurboGears).
A solução é forçar o SQLObject a usar UTF-8 internamente e desativar conversões desnecessárias sendo feitas por ele. Para isso modifique sua URI de conexão para algo como:
sqlobject.dburi=
"mysql://root:@localhost:3306/fliki?use_unicode=1&sqlobject_encoding=utf8"
Dependendo da versão do SQLObject pode ser necessário também adicionar o parâmetro charset=utf8 à URI.







Comentários Recentes