#define
 Define uma constante manifesta ou pseudo funçao
------------------------------------------------------------------------------

 Sintaxe

     #define <idConstante> [<textoResult>]
     #define <idFunçao>([<lista arg>]) [<exp>]

 Argumentos

     <idConstante> é o nome do identificador a ser definido.

     <textoResult> é o texto substituto opcional a ser colocado onde
     quer que um a <idConstante> seja encontrada.

     <idFunçao> é a definiçao da pseudo-funçao com uma lista de
     argumentos opcionais (<lista arg>).  <idFunçao> deve ser especificada
     seguindo uma abertura de parênteses especificada sem qualquer espaço em
     branco, e <lista arg> deve ser seguida de um fecha parênteses.

     <exp> é a expressao de substituiçao a ser substituída quando a
     pseudo-funçao for encontrada.  Esta expressao deve estar entre
     parênteses para garantir a precedência da avaliaçao quando a
     pseudo-funçao for expandida.

     -----------------------------------------------------------------------
     . Nota

     #define é sensível a maiúsculas e minúsculas enquanto que #command e
     #translate nao.
     -----------------------------------------------------------------------

 Descriçao

     A diretiva #define define um identificador e opcionalmente associa um
     texto de substituiçao.  Se o texto de substituiçao for especificado,
     ele opera de uma forma parecida como a troca de um string por outro que
     encontramos em qualquer editor de texto.  Como o código fonte é
     processado pelo pré-processador, a linha é percorrida em busca de
     identificadores.  Se um for encontrado, o texto de substituiçao é
     colocado em seu lugar.

     Identificadores especificados com #define seguem as regras de nomes do
     Clipper.  Podem conter caracteres alfabéticos ou numéricos, inclusive
     sublinhas.  Também serao considerados apenas os 10 primeiros caracteres
     do nome.  Identificadores definidos, entretanto, diferem dos outros
     identificadores pois fazem distinçao entre maiúsculas e minúsculas.
     Como convençao, costuma-se especificá-los como maiúsculas para
     diferenciá-los de outros identificadores presentes no programa.
     Adicionalmente, identificadores sao especificados com um prefixo de uma
     ou duas letras para garantir unicidade.  Veja exemplos em um dos
     arquivos header no diretório \CLIPPER5\INCLUDE.

     Quando especificado, cada linha deve ocorrer em uma linha por si.
     Diferente de declaraçoes mais de uma diretiva nao pode ser especificada
     na mesma linha, embora a definiçao possa ter continuidade na linha
     posterior usando um ponto e vírgula.  Cada diretiva #define é
     especificada seguindo um ou mais espaços (espaços ou tabs), um
     identificador único, e o texto de substituiçao opcional.  Definiçoes
     podem ser aninhadas permitindo um identificador definir outro.

     Um identificador definido tem uma abrângencia léxica parecida com a de
     uma variável static.  Ele somente é válido no arquivo (.prg) no qual
     foi definido a menos que definido no STD.CH ou no header especificado
     pela opçao de compilador /U.  De forma diferente de uma variável
     static, um identificador é visível a partir do ponto onde é definido
     até o ponto onde for indefinido (com #undef) redefinido, ou encontrado
     o fim de programa.

     Definiçoes existentes podem ser redefinidas ou indefinidas (com
     #undef).  Para redefinir um identificador,  especifique um novo #define
     com o mesmo nome de identificador e o texto desejado.    A definiçao
     corrente será entao anulada pela nova e um aviso do compilador será
     emitido caso a redefiniçao seja inadvertida.  Para retirar uma
     definiçao, especifique uma diretiva #undef com o nome do identificador
     desejado.

     Diretivas #define possuem três propósitos básicos:

       Definir um identificador de controle para #ifdef e #ifndef

       Definir uma constante manifesta --um identificador definido
        para representar um valor constante

       Definir uma pseudo-funçao de compilador

     A discussao a seguir expande-se em como estas três formulaçoes da
     diretiva #define podem ser usadas nos seus programas.

     Identificadores de pré-processador

     A diretiva #define mais básica define um identificador sem texto de
     substituiçao.  Este tipo de identificador pode ser usado quando voce
     necessitar testar a existência de um identificador com #ifdef ou
     #ifndef.  Isto é útil para compilaçao condicional para excluir ou
     incluir código durante a compilaçao.  Este tipo de identificador pode
     ser definido também por meio da opçao de compilador /D na linha de
     comando deste.  Veja exemplos abaixo.

     Contantes Manifestas

     A segunda forma da diretiva #define atribui um nome para um valor
     constante.  Esta forma de identificador é referenciada como constante
     manifesta.  Como exemplo, uma constante manifesta pode ser definida
     pelo código INKEY() associado com a tecla apertada, como em:

     #define K_ESC  27
     IF LASTKEY() = K_ESC
        .
        . <declaraçoes>
        .
     ENDIF

     Onde quer que uma constante manifesta seja encontrada pelo
     pré-processador quando examinando um a linha, ela será substituída pelo
     texto.

     Embora isto possa ser conseguido definindo uma variável, existem várias
     vantagens em usar uma constante manifesta.  Primeiro, o compilador pode
     gerar um código mais compacto e mais rápido para constantes do que para
     variáveis.  Segundo, variáveis possuem um consumo de memória enquanto
     que constantes manifestas nao o possuem, assim economizamos memória e
     óbviamente aumentamos a velocidade de execuçao.  Finalmente, usando uma
     variável para representar um valor constante é conceitualmente absurdo,
     pois uma variável pode ter seu valor alterado e uma constante
     óbviamente nao.

     Uma constante manifesta é usada em lugar de uma constante por várias
     razoes.  Primeiro, por que aumenta a legibilidade.  No exemplo acima, a
     constante manifesta indica mais claramente a tecla representada do que
     o valor da tecla por si.  Segundo, constantes manifestas localizam a
     definiçao de constantes em um único local, tornando modificaçoes
     simples de serem executadas e dessa forma aumentando a confiabilidade.
     Terceiro, como um efeito colateral da segunda razao, é que a constante
     manifesta isola coisas específicas do ambiente ou implementaçao quando
     estas coisas sao representadas por valores constantes.

     Para isolar mais ainda os efeitos de modificaçoes, constantes
     manifestas e outros identificadores devem ser agrupados em arquivos
     cabeçalho, permitindo a você, compartilhar identificadores entre
     arquivos de programa (.prg), aplicaçoes e grupos de programadores.
     Usando esta metodologia, definiçoes podem ser padronizadas para uso
     através da equipe de desenvolvimento.  Arquivos header sao intercalados
     com o arquivo corrente usando a diretiva #include.

     Para exemplos de arquivos header, leia os arquivos header que se
     encontram no diretório \CLIPPER5\INCLUDE.

     Pseudo-funçoes de Compilador

     Adicionalmente a definir constantes, a diretiva #define pode ser usada
     para definir pseudo-funçoes que sao resolvidas em tempo de compilaçao.
     Um pseudo-funçao é um identificador seguido de um abre parênteses, e
     seguindo, sem espaços, por uma lista de argumentos e de um fecha
     parênteses e da expressao de substituiçao.  Por exemplo:

     #define AREA(nTam, nLarg)  (nTam * nLarg)
     #define SETVAR(x, y)  (x := y)
     #define MAX(x, y)  (IF(x > y, x, y))

     Pseudo-funçoes diferem de constantes manifestas por permitirem
     argumentos.  Onde quer que o pré-processador veja uma chamada de funçao
     que tenha equivalência com a definiçao de pseudo-funçao, ele substitui
     a chamada de funçao com a expressao.  Os argumentos da chamada de
     funçao sao transportados para dentro da expressao de substituiçao via
     os nomes especificados na lista de argumentos da definiçao do
     identificador.  Quando a expressao de substituiçao é trocada pela
     pseudo-funçao, os nomes correspondentes na expressao de substituiçao
     sao expandidos como texto do argumento.  Por exemplo:

     ? AREA(10, 12)
     SETVAR(nValor, 10)
     ? MAX(10, 9)

     será substituído por:

     ? (10 * 12)
     (nValue := 10)
     ? (IF(10 > 9, 10, 9))

     Quando definindo pseudo-funçoes com #define existem várias
     consideraçoes importantes.  Primeira, é importante incluir a expressao
     resultante entre parênteses para forçar a ordem correta de avaliaçao.
     Isto é particularmente importante quando se trata de expressoes
     numéricas.  Segundo, com pseudo-funçoes, todos os argumentos devem ser
     especificados.  Se nao o forem, a chamada de funçao nao é expandida
     como pseudo-funçao e a saída do pré-processador para o compilador fica
     como foi encontrado.  Esta é uma das deficiências de pseudo-funçoes.

     Quando for decidir sobre o uso de uma pseudo-funçao ou uma funçao de
     usuário, existem várias consideraçoes.  Pseudo-funçoes nao possuem a
     perda de tempo de chamada de uma rotina, nao causam consumo de memória
     e geralmente sao mais rápidas.  Pseudo-funçoes, entretanto, sao muito
     mais difíceis de depurar dentro do Debugger, tem uma abrangéncia
     diferente de funçoes e procedures declarados, nao permitem saltar
     argumentos, e sao sensíveis a maiúsculas e minúsculas.

     Muitas destas deficiências podem ser retificadas definindo uma funçao
     com a diretiva #translate.  Em particular, funçoes #translate nao sao
     sensíveis a maiúsculas/minúsculas e permitem argumentos opcionais.
     Veja a diretiva #translate neste capítulo para maiores informaçoes.

 Exemplos

       O exemplo a seguir demonstra como a existência de uma
        constante manifesta pode condicionalmente controlar a compilaçao de
        código para o depurador:

        #define DEBUG
        .
        . <declaraçao>
        .
        #ifdef DEBUG
           Assert(FILE("System.dbf"))
        #endif

       Este exemplo mostra como uma constante manifesta é definida e
        usada em substituiçao ao valor INKEY():

        #define K_ESC  27
        .
        . <declaraçoes>
        .
        IF INKEY() != K_ESC
           DoIt()
        ELSE
           StopIt()
        ENDIF

       Este exemplo demonstra definiçoes de pseudo-funçoes para as
        funçoes padrao Clipper, MAX() e ALLTRIM():

        #define MAX(arg1, arg2)   (IF(arg1 > arg2, arg1, arg2))
        #define ALLTRIM(cString)  (RTRIM(LTRIM(cString)))
        .
        . <declaraçoes>
        .
        ? MAX(1, 2)
        ? ALLTRIM("  Oi Mundo!  ")
 To download this example - click here.

See Also: #command #ifdef #ifndef #undef