Caloni.com.br     Archive     Feed     Author

11°. Encontro C/C++ Brasil -- Inscrições

Agora é pra valer!

O Call for Papers já iniciou há duas semanas e deverá ser encerrado no final de Fevereiro, quando publicaremos o cronograma do nosso evento. Até lá a página oficial do evento deverá ser atualizada com coisas a mais do que os dois coffee breaks. Porém, antes que o preço aumente, você já pode garantir o seu lugar e pagar mais barato. Para uma dica do que poderá ser selecionado de palestras compilamos uma lista de palavras-chave.

Porém, fora as palestras, teremos a chance de conversar sobre os mais diversos assuntos que giram em torno de tecnologia, C/C++ e todas as áreas em que essas linguagens são usadas. O pessoal de embarcados costuma marcar uma presença forte por lá, além de algum pessoal de finanças, segurança da informação, projetos open-source, matemática, acadêmicos e, acredite se quiser, até programadores de device drivers para o kernel do Windows.

A foto de abertura do post é de uma série muito bem-humorada chamada Russian Nerds Party.

11°. Encontro C/C++ Brasil -- Call for Papers

Acho que já está na hora de nos reencontrarmos, né?

A comunidade CCPP Brasil está preparando mais um daqueles eventos em que conversaremos sobre nossa maior paixão: B! BCPL! C e C++!

#include <ccpp-people.h>

int main()
{
    std::cout << "Hello, C/C++ Brasil!\n";
}

Então vamos aos detalhes:

Chave Valor
Data 2015-03-28
Local Micro$oft Brasil
Palestras

Ops, deu um errinho acima. Acho que é porque ainda não temos as palestras.

Quer colaborar? Não deixe de preencher então o nosso formulário do Call for Papers!

Alguma dúvida antes de preencher? Fale conosco na thread sobre o CFP!

Se conhece alguém que gostaria de participar do evento, palestrante ou não, por favor, espalhe a notícia o mais rápido possível. Quanto mais cedo soubermos quantas pessoas irão, melhor fica organizar melhor nosso reencontro.

As próximas notícias continuarei divulgando aqui e em fórum C/C++. Fique atento.

Origem do tipo char

Programadores C e C++, preparem-se para explodir as cabeças!

No princípio... não, não, não. Antes do princípio, quando C era considerada a terceira letra do alfabeto e o que tínhamos eram linguagens experimentais para todos os lados, dois famigerados srs. dos Laboratórios Bell, K. Thompson e D. Ritchie, criaram uma linguagem chamada B. E B era bom.

O bom de B estava em sua rica expressividade. Sua gramática extremamente simples. Tão simples que o manual da linguagem consistia de apenas 30 páginas. Isso é menos do que as 32 palavras reservadas de C.

As instruções eram definidas em termos de if's e goto's e as variáveis eram definidas em termos de um padrão de bits de tamanho fixo -- geralmente a word da plataforma -- que utilizada em expressões definiam seu tipo; esse padrão de bits era chamado rvalue.

Como esse padrão de bits nunca muda de tamanho, todas as rotinas da biblioteca recebiam e retornavam sempre valores do mesmo tamanho na memória. Isso na linguagem C quer dizer que o char da época ocupava tanto quanto o int. Existia inclusive uma função que retornava o caractere de uma string na posição especificada:

c = char(string, i); // the i-th character of the string is returned

Sim! Char era uma função, um conversor de "tipos". No entanto a própria variável que armazenava um char tinha o tamanho de qualquer objeto da linguagem. Esse é o motivo pelo qual, tradicionalmente, as seguintes funções recebem e retornam ints em C:

int getchar( void ); // read a character from stdin
int putchar( int c ); // writes a character to stdout
void *memset( void *dest, int c, size_t count ); // sets buffers to a specified character

Links interessantes para filólogos de plantão:

RIP, Alberto

Acho que como muitos aqui de vocês, eu sou (fui?) um fã condicional de Alberto Fabiano, o mestre em várias coisas, não se restringindo apenas à informática. Alberto, é preciso dizer, foi um hacker de verdade.

Ultimamente ando fuçando nas minhas mensagens do GMail procurando por posts que se perderam no tempo. Acabei encontrando um email que o Alberto me mandou em 2006 comparando nossas evoluções na área. Não é preciso dizer que a minha evolução ficou para trás em algumas centenas de anos perto dele, mas mesmo assim ele teve a "humildade" e uma infinita modéstia de comparar-nos em alguns aspectos de nossas vidas profissionais, como termos começado a programar com Quick BASIC e gostar de Segurança da Informação.

Não fiz nenhum post à época da sua morte porque não achei adequado, nem o momento. Porém, de vez em quando, acredito que é necessário se lembrar dos melhores, assim como muitos de nós fizeram com o mestre Dennis Ritchie um tempo atrás.

Portanto, segue o email, e uma pequena lembrança. Que a sabedoria do Alberto esteja de alguma forma infectando o Universo e que seus átomos em milhões ou bilhões de anos reconstruam mais Albertos para espalhar inteligência e bom senso por todo o mundo.

Olá Caloni,

  Por um acaso, antes de adicionar seu site-blog no
  bookmark  do meu blog, fui dar uma olhada no about do
  seu site e fiquei surpreso como temos pontos em comuns
  em nossos perfis... com sutis diferenças... 

  Vc começou a programar com o Quick Basic, eu também
  programei com o Quick Basic mas comecei com o Gw-Basic
  em 1990, depois fui pro Basica IBM, depois fui pro
  Cobol mas como eu trabalhava com DBase III Plus logo
  fui ficando curioso em como automatizar alguns
  procedimentos e fiz meus primeiros PRG e com o tempo
  fui automatizado... migrei coisas para o Cobol,
  Clipper, Joiner, fiz vários experimentos com C, C++
  mas em 1999 eu acabei partindo para área de
  infra-estrutura onde fiquei por + de 2 anos... Neste
  meio tempo, mais por curiosidade e por consequencia
  natural da montagem de um Z80 em clube, cheguei a
  programar em ASM e C para Z80; que acabaram me levando
  ao PIC... 

  Sempre gostei do SCUA, achei muito curioso o fato de
  vc ter trabalhado lá, pois sempre tive um pé na área
  de segurança, tanto que meu TCC foi de graduação, pós
  em Engenharia de Software e o de uma pós-graduação em
  Security no IBPI (aí já é muito óbvio) foi de
  segurança... 

 Quase trabalhei para a OpenCS, você trabalha pra eles;
 achei isto muito interessante!

  Como centenas, acho que como alguns milhares de
  profissionais eu já estudei no IBTA; fiz Network
  Academy e quase fiz uma pós lá; não fiz por pouco. 

  Tenho programas espalhadas por aí, que nem sei se
  ainda são todos utilizados, em Cobol, Clipper, Joiner,
  SmallTalk (sim é isto mesmo, olhando para trás nem eu
  acredito nisto) assim como Java, pois é... VB 6, Web
  Pages em Perl, PHP, ASP, JSP e ultimamente em Python.
  Depois de um tempo meio fora, voltei a programar em C
  e ASM por causa de um súbito retorno ao envolvimento
  com microcontroladores à uns 4 anos atrás, e aí foi
  pintando o interesse em desenvolver em C para Linux,
  então-se voltei ao C++; porém agora com uma base muito
  mais solida de programação do que 10 anos antes... E
  tem sido à C++ no qual tenho me dedicado nos últimos 3
  anos; tenho que confessar que o que andei fazendo em
  VB nos últimos anos foi apenas pq eu não sabia como
  fazer exatamente em C++ ou (ouve casos) que por pressa
  e falta de suporte a bibliotecas específicas para C++
  (dá para acreditar?) e é isto... não nego que tenho
  muito o que aprender em matéria de C++, e pretendo! 

   Também não nego que já andei dando minhas cacetadas
   com Visual Objects (argh), Delphi, Clipper com Max e
   FiveWin, Lisp, RPG (por pura casualidade) além de
   Korn Script (também por força da ocasição), VBScript,
   JSCript, JavaScript (conseqüência natural ao se mexer
   com ASP e PHP; Java a princípio por curiosidade,
   depois por questão de sobrevivência e ultimamente
   apenas por comodidade ao mexer com J2ME.... 

   Bem... de qualquer forma, seu blog está no meu
   bookmark... e é isto aí!  Estarei na DevTech...

Att []´s..

Por que o Visual Studio gera executáveis mutantes

Mutantes

Esse é um post antigo que encontrei no meio dos meus emails de 2006, mas que contém uma boa dica para quem já entendeu o passo-a-passo da compilação, mas ainda tem sérios problemas quando os projetos ficam gigantes.

Essa é a segunda vez que encontro esse mesmo problema. Como acredito que outras almas podem estar sofrendo do mesmo mal, coloco aqui uma breve descrição de como o VC8 faz para gerar um executável que, mesmo não dependendo das DLLs de runtime, não são executados em sistemas que suportam a interpretação do ".manifest". De canja, um pequeno programa que exibe a lista dos programas instalados no sistema.

Primeiro, precisamos de um solution que contenha um projeto console e uma LIB. O projeto console deve usar a LIB para fazer alguma coisa. No exemplo abaixo, estarei listando os programas instalados no Windows (os mostrados no painel de controle através da opção "Adicionar/remover programas".

/** library.h
*/
#pragma once
#include <string>
#include <vector>

typedef std::vector<std::string> InstalledSoftwareList;
int getInstalledSoftware(InstalledSoftwareList&);



/** library.cpp
*/
#include "library.h"
#include <windows.h> // aqui precisamos do windows para as funções de registro
#include <tchar.h> // suporte a unicode condicional

#define SW_ROOT_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
#define SW_DISPLAY_NAME "DisplayName"

/** Retorna o número de elementos em um array. */
template<typename T, size_t Sz>
DWORD SizeofArray(const T(&arr)[Sz]) { return Sz; }


/** Retorna lista com descrição de cada programa instalado no sistema. */
int getInstalledSoftware(InstalledSoftwareList& installedSoftware)
{
   HKEY swRoot = NULL;
   DWORD err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(SW_ROOT_KEY), 0, KEY_READ, &swRoot);

   if( err == ERROR_SUCCESS )
   {
      DWORD swIndex = 0;
      TCHAR swKeyName[MAX_PATH] = _T("");

      // para cada chave dentro da raiz de programas instalados
      while( (err = RegEnumKey(swRoot, swIndex++, swKeyName, SizeofArray(swKeyName))) 
         == ERROR_SUCCESS )
      {
         HKEY swCurrent = NULL;
         err = RegOpenKeyEx(swRoot, swKeyName, 0, KEY_READ, &swCurrent);

         if( err == ERROR_SUCCESS )
         {
            CHAR swDisplay[MAX_PATH] = ""; // vamos obter a string já em mb
            DWORD swDisplaySz = SizeofArray(swDisplay);

            if( (err = RegQueryValueExA(swCurrent, SW_DISPLAY_NAME, 0, NULL, 
               reinterpret_cast<PBYTE>(swDisplay), &swDisplaySz)) == ERROR_SUCCESS )
            {
               installedSoftware.push_back(swDisplay);
            }

            RegCloseKey(swCurrent);
         }
      }

      // se não tem mais itens, então não é um erro
      if( err == ERROR_NO_MORE_ITEMS )
         err = ERROR_SUCCESS;
      RegCloseKey(swRoot);
   }
   return int(err);
}


/** console.cpp
*/
#include "../library/library.h" // include da nossa lib
#include <algorithm>
#include <iostream>

using namespace std;


int main()
{
   int ret;
   InstalledSoftwareList swList;

   cout << "MSVC Mutant - v. beta\n"
      << "by Wanderley Caloni (www.caloni.com.br)\n\n";


   // obtém a lista de programas instalados e exibe na tela
   ret = getInstalledSoftware(swList);

   if( ret == 0 )
   {
      cout << "Programs installed on your system\n"
         << "=================================\n";
      copy(swList.begin(), swList.end(), ostream_iterator<string>(cout, "\n"));

   }
   else
      cout << "Error " << ret << " trying to list installed programs.\n";

   return ret;
}

__Observação importante: para ignorar todas as estripulias da versão Debug, todos os testes foram compilados em Release.

Primeiramente, modifico a configuração padrão dos dois projetos para não depender da DLL de runtime do VC. Isso está em Project, Properties, C/C++, Code Generation, Runtime Library. Depois executo em uma máquina virtual sem as runtimes do VC8 instaladas:

MSVC Mutant - v. beta
by Wanderley Caloni (www.caloni.com.br)

Programs installed on your system
=================================
Windows XP Service Pack 2
WebFldrs XP
VMware Tools

Perfeito. Exatamente o que eu queria: um executável console que não dependesse de DLL nenhuma exceto as que já estão instaladas em um Windows ordinário.

Agora, vamos imaginar que esse é um daqueles projetos enormes de 5 * 10 ^ 42 de linhas (obs: dramatização) e que meu aplicativo console está linkado com cerca de 3 * 10 ^ 666 de LIBs. E uma delas (a library do exemplo) está com a configuração original, ou seja, com a dependência da DLL de runtime. E ela usa a STL. Provavelmente o aplicativo console não irá compilar, mas isso não é problema, pois estamos acostumados a colocar a msvcrt.lib na lista de LIBs ignoradas, pois em muitos outros casos (que não vale a pena discutir aqui) esse workaround é válido. E tudo volta a funcionar. Quer dizer, linkar:

O sistema no pode executar o programa especificado.

Tudo bem, meu executável não é mutante ainda. Mas agora vamos trocar a chamada da nossa função que usa STL por uma função que não usa:

/** library.h
*/
int doesNothing();


/** library.cpp
*/

/** Essa função não faz nada. Quer dizer, ela retorna 0. Mas é só isso. */
int doesNothing()
{
   return 0;
}


/** console.cpp
*/
#include "../library/library.h" // include da nossa lib

int main()
{
   int ret;

   // não faz nada. bom, chama uma função. mas isso é quase nada.
   ret = doesNothing();

   return ret;
}
Linking
=======
library.lib(library.obj) : warning LNK4049: locally 
 defined symbol __invalid_parameter_noinfo imported

Running
=======
O sistema no pode executar o programa especificado.

Depends
=======
Error: The Side-by-Side configuration information in "blablabla\CONSOLE.EXE" 
 contains errors.
Falha na inicialização do aplicativo devido a configuração incorreta.
A reinstalação do aplicativo pode resolver o problema (14001).

Agora sim, a mutação fez efeito! Temos um aplicativo que não depende da DLL de runtime, mas que no meio das n LIBs que ele utiliza existe uma configurada com a dependência. Ignorando a msvcrt.lib e um warning na compilação encontramos uma mensagem de erro um tanto exdrúxula.

Até agora, a maneira que eu tenho utilizado para rastrear esse problema é não ignorar a msvcrt e ir tirando as dependências das LIBs pouco a pouco, até que ocorra o erro de símbolo duplicado. Algo assim:

MSVCRT.lib(ti_inst.obj) : error LNK2005: "private: __thiscall 
 type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) 
 already defined in LIBCMT.lib(typinfo.obj)
MSVCRT.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall 
 type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) 
 already defined in LIBCMT.lib(typinfo.obj)
LINK : warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; 
 use /NODEFAULTLIB:library
Blablabla\console.exe : fatal error LNK1169: one or more multiply defined symbols found

Se você tiver realmente 3 * 10 ^ 666 de LIBs, boa sorte =).