[Linguagem C] Pré-processamento e palavras-chave, muitas vezes negligenciados, mas pontos importantes

Índice

Prefácio:

1. Pré-tratamento:

O papel do pré-processamento e comandos comumente usados

(1) O processo de compilação da linguagem C:

(2) Comandos de pré-processamento comumente usados

A função e exemplos de comandos de pré-processamento

(1) Definição de macro

(2)#erro

2. Palavras-chave:

palavra-chave const:

(1) Função

(2) Semelhanças e diferenças com instruções pré-compiladas

palavra-chave estática:

(1) Ao modificar variáveis ​​locais:

(2) Ao modificar variáveis ​​globais:

(3) Ao modificar a função:

Palavra-chave volátil:

(1) Função:

(2) Exemplos específicos:

palavra-chave typedef:

(1) Função

(2) A diferença com #define

tamanho da palavra-chave:

(1) Função 

(2) função strlen ()

palavra-chave externa:

(1) Função   

(2) Pontos a observar

registrar palavra-chave:

(1) Função

(2) Pontos a observar

palavra-chave automática:

(1) Função

(2) Cenários de aplicação


Prefácio:

Quando aprendermos incorporado pela primeira vez, compraremos uma placa de desenvolvimento para começar. Nas funções da biblioteca que chamamos, usaremos alguns comandos de pré-processamento e algumas palavras-chave. São pontos que muitas vezes ignoramos e não usamos, mas na verdade são Ela tem um papel importante , e são justamente esses os pontos que os entrevistadores da empresa focam

1. Pré-tratamento:

O papel do pré-processamento e comandos comumente usados

(1) O processo de compilação da linguagem C:

ae08295b3a6e420d9b6121ac2baecf96.pngO papel do pré-processamento: inclusão de arquivo de cabeçalho (#include), substituição de macro (#define), compilação condicional (#ifdef, #ifndef), remoção de comentários e adição de números de linha.

(2) Comandos de pré-processamento comumente usados

nome de pré-processamento significado
#definir definição de macro
#incluir Faz com que o compilador incorpore outro arquivo de origem no arquivo de origem com #include
#if、#endif Se a expressão constante atrás de #if for verdadeira, compile o código entre ela e #endif, caso contrário pule.
#outro Onde #if falha, #else estabelece outra alternativa
#ifdef、#ifndef Significa respectivamente "se definido" e "se não definido", outra forma de compilação condicional
#erro Ao compilar o programa, enquanto # erro for encontrado, um erro de prompt de compilação será gerado e a compilação será interrompida.

A função e exemplos de comandos de pré-processamento

(1) Definição de macro

Vantagens : reutilização de código; desempenho aprimorado
Desvantagens : não depurável (substituído no estágio de pré-compilação); nenhuma verificação de segurança de tipo; baixa legibilidade e propensa a erros.

  • Macro sem argumentos: geralmente usado para substituir quaisquer constantes e strings, etc.
#define M 5                // 宏定义
#define PI 3.14            // 宏定义
int a[M];                  // 会被替换为: int a[5];
int b = M;                 // 会被替换为: int b = 5;
printf("PI = %.2f\n", PI); // 输出结果为: PI = 3.14
  • Macro de parâmetros: É semelhante a uma função, mas não é uma função.
    • A macro com parâmetros é apenas uma simples substituição de caractere no estágio de pré-processamento da compilação; enquanto a função é chamada e retornada em tempo de execução.
    • A substituição de macro não leva em conta o tempo de execução, apenas o tempo de compilação; enquanto as chamadas de função levam em conta o tempo de execução (unidade de alocação, campo reservado, passagem de valor, retorno).
    • Macros com parâmetros não alocam memória quando são processadas; chamadas de função alocam memória temporária.
    • Não há problema de tipo em macros, o nome da macro não tem tipo e seus parâmetros também não têm tipo; enquanto os parâmetros reais e os parâmetros formais na função devem definir tipos e os requisitos de tipo dos dois são consistentes.
  • Exemplo concreto:
//输入两个参数并返回较小的一个
//应用了三目条件运算符
#define  MIN(A, B)  ((A) <= (B) ? (A) : (B))

//已知数组table,用宏求数组元素个数
//数组元素个数 = 数组长度 / 数组元素长度
#define  COUNT(table)  (sizeof(table) / sizeof(table[0]))

Nota: Se *p++ for colocado no corpo da macro, o ponteiro p realizará duas operações de auto-incremento. 

(2)#erro

Função : Ao compilar o programa, enquanto #error for encontrado, um erro de compilação aparecerá.

Cenário de aplicação : Quando o programa é relativamente grande, algumas definições de macro são geralmente especificadas externamente (como makefile) ou especificadas no arquivo de cabeçalho do sistema. Quando você não tem certeza se XXX está definido no momento, você pode usar #error

Um exemplo específico é o seguinte: 

//如果遇到abc时,执行#error
#ifdef abc  
#error "abc has been defined"  
#else  
…  
#endif 

2. Palavras-chave:

Aqui nos concentramos nas palavras-chave importantes que muitas vezes ignoramos, incluindo:

  • Classe de armazenamento: const , static , extern, register, auto
  • Tipos de dados: voláteis , typedef
  • Operador: sizeof

palavra-chave const:

(1) Função

  • Uma palavra-chave que define uma variável somente leitura. O valor de uma variável ou objeto de tipo constante não pode ser alterado ou atualizado.
  • Após a modificação const, o programa não deve tentar modificá-lo.

(2) Semelhanças e diferenças com instruções pré-compiladas

  • O mesmo: ambos podem ser usados ​​para definir constantes.
  • Diferente: const tem um tipo de dados e o compilador pode fazer verificação de tipo estático; enquanto as definições de macro não têm tipo, o que pode causar erros de tipo

palavra-chave estática:

(1) Ao modificar variáveis ​​locais:

  • Mudou seu local de armazenamento, armazenado na área estática;
  • Ao mesmo tempo, seu ciclo de vida é alterado para todo o programa fonte, portanto, ele é inicializado apenas uma vez e é automaticamente inicializado em 0 se não for explicitamente inicializado.

(2) Ao modificar variáveis ​​globais:

  • Alterado seu escopo para que só possa ser acessado por funções utilizadas no arquivo.

(3) Ao modificar a função:

  • Alterado seu escopo e só pode ser chamado por outras funções neste arquivo.

Palavra-chave volátil:

(1) Função:

  • Ao encontrar uma variável declarada com esta palavra-chave, o compilador não fará mais suposições ( otimização ) sobre o código que acessa a variável, fornecendo assim acesso estável a endereços especiais.
  • O otimizador deve reler cuidadosamente o valor da variável toda vez que usar uma variável volátil modificada , em vez de usar um backup armazenado em um registro . Por exemplo: registradores de hardware de dispositivos paralelos (por exemplo: registradores de status)

(2) Exemplos específicos:

Um parâmetro pode ser const e volátil? Um ponteiro pode ser volátil? O que há de errado com a função abaixo?

int square(volatile int *ptr)   
{   
    return *ptr * *ptr;   
}   

① Sim. Um exemplo é o registrador de status somente leitura, que é volátil porque pode ser alterado inesperadamente e const porque o programa não deve tentar modificá-lo. 

②Sim. Um exemplo é quando uma rotina de serviço de interrupção modifica um ponteiro para um buffer. 

③Esta função originalmente deseja obter o quadrado do valor apontado pelo ponteiro *pr, mas *ptr aponta para um parâmetro volátil e o compilador gerará um código semelhante ao seguinte.

int square(volatile int *ptr)   
{   
    int a, b;   
    a = *ptr;   
    b = *ptr;   
    return a * b;   
} 

palavra-chave typedef:

(1) Função

  • Na linguagem C, geralmente é usado para declarar um sinônimo para um tipo de dados existente
  • Também é possível fazer pré-processamento como

(2) A diferença com #define

#define  dPS  struct s *   
typedef  struct s *  tPS;  
dPS  p1, p2;   
tPS  p3, p4;   
  • define é uma substituição de string, então dPS p1, p2; é realmente escrito como struct s * p1, p2; ou seja, define p1 como um ponteiro para uma estrutura e p2 como uma estrutura real.
  • tPS p3, p4;; define dois ponteiros p3 e p4 corretamente.

tamanho da palavra-chave:

(1) Função 

  • Usado para calcular o número de bytes de memória ocupados por variáveis ​​e tipos de dados.
  •  sizeof(array name) obtém o número de bytes ocupados pelo array. sizeof (string nome do ponteiro) obtém o número de bytes ocupados pelo ponteiro.

(2) função strlen ()

  • Usado para testar o número de bytes ocupados pela string, excluindo o caractere final '\0'.
  • strlen (nome da matriz de caracteres) obtém o número de bytes ocupados pela string e strlen (nome do ponteiro da string) obtém o número de bytes ocupados pela string.

palavra-chave externa:

(1) Função   

  • extern entra em ação durante a fase de vinculação.
  • Ele é usado para se referir a variáveis ​​globais entre arquivos, ou seja, para se referir a uma variável global que foi definida em outros arquivos neste arquivo.

(2) Pontos a observar

  • Ele não pode ser inicializado quando é referenciado, como extern var, mas não extern var = 0.

registrar palavra-chave:

(1) Função

  • O compilador colocará variáveis ​​modificadas por registradores nos registradores da CPU tanto quanto possível para acelerar sua velocidade de acesso, geralmente usado para variáveis ​​usadas com frequência

(2) Pontos a observar

  • A variável de registro pode não ser armazenada na memória, então você não pode usar & para obter o endereço da variável;
  • Somente variáveis ​​locais e parâmetros formais podem ser usados ​​como variáveis ​​de registro;
  • O número de registros é limitado e muitas variáveis ​​de registro não podem ser definidas.

palavra-chave automática:

(1) Função

  • É utilizado para definir variáveis ​​locais automáticas.As variáveis ​​locais automáticas são estabelecidas ao entrar no bloco de comandos que declara a variável, e são canceladas ao sair do bloco de comandos.São utilizadas somente dentro do bloco de comandos.
  • Quando auto é modificado, o tipo de dados pode ser inferido automaticamente.

(2) Cenários de aplicação

  • É usado para substituir a declaração de variável que é longa e complicada, e o escopo de uso da variável é específico.
  • O i no loop for deduzirá automaticamente seu tipo no tempo de compilação, sem que tenhamos que definir explicitamente a string longa.

Nota: Não é recomendado usar auto desta forma quando estiver realmente programando, pois é mais claro e fácil escrever diretamente o tipo da variável.

Acho que você gosta

Origin blog.csdn.net/weixin_42373086/article/details/129874871
Recomendado
Clasificación