minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
na última edição[Linguagem C] - Explicação detalhada do pré-processamento (Parte 2) Durante o estudo, apresentamos detalhadamente o conhecimento relevante de macros no pré-processamento. Acredito que todos ganharão muito. Não se preocupe, vamos continuar aprendendo outros conhecimentos sobre pré-processamento nesta edição.
# 运算符
Converte um argumento de uma macro em uma string literal.É permitido aparecer na lista de substituição de macros por parâmetros.# 运算符
A operação realizada pode ser entendida como “stringificação”
O que isso significa?
Vamos fazer um prenúncio primeiro:
int mian()
{
printf("hello" "worldn");
printf("helloworldn");
return 0;
}
Qual é a diferença entre as duas linhas de código acima? Vamos dar uma olhada juntos:
Como você pode ver, o efeito de duas cordas e uma corda é o mesmo.C语言会把两个字符串天然连成一个字符串
, adicionar um espaço no meio é inútil.
Agora há uma cena como esta:
int main()
{
int a = 1;
printf("The value of a is %dn", a);
int b = 20;
printf("The value of b is %dn", b);
float f = 8.5f;
printf("The value of f is %fn", f);
return 0;
}
Descobrimos que a lógica das três linhas de código é muito相像
Sim, mas existem些许不同
。
Então pensamos, já que eles são tão parecidos, poderíamos colocá-los封装成一个函数
, para facilidade de uso?
Mas as funções não podem realizar esta função.
então o que devemos fazer?
Podemos tentar usar macros para resolver isso
#define Print(n, format) printf("The value of n is " format "n", n)
int main()
{
int a = 1;
Print(a, "%d");
//printf("The value of a is %dn", a);
int b = 20;
Print(b, "%d");
//printf("The value of b is %dn", b);
float f = 8.5f;
Print(f, "%f");
//printf("The value of f is %fn", f);
return 0;
}
resultado da operação:
nos descobrimos nãonãoãoãoãoãoãoão Não mudou, então como devo modificá-lo?
É aqui que nosso operador # deve ser usado:# Converte um argumento de uma macro emstring literal,Agora mesmo nãonãoãoãoãoãoãoão tornar-se “ n ” “ n”“nãoãoãoãoãoãoão”
Neste momento, podemos usar o método de emenda para nos tornarmos
#define Print(n, format) printf("The value of " #n " is " format "n", n)
não sabe?Você entenderá depois de ler a explicação abaixo.
##
pode estar localizado neleOs símbolos em ambos os lados são combinados em um símbolo, que permite a definição de macro从分离的文本片段创建标识符
。##
é chamadocolagem de marcas .Tal conexão deve produzir um合法
indicador, caso contrário o resultado será indefinido.
Já dissemos que para escrever uma função que encontre o valor maior de dois números, precisamos escrever funções diferentes para tipos de dados diferentes.
int int_max(int x, int y)
{
return x > y ? x : y;
}
float float_max(float x, float y)
{
return x > y ? x : y;
}
Isto é inevitavelmente muito complicado e há muitas semelhanças entre as duas funções.
Existe alguma maneira de criar rapidamente essa função?como uma funçãoMofoMesmo, basta aplicar uma função e ela sairá
Podemos escrever um assim宏
:
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
GENERIC_MAX(int); //相当于定义了一个函数int_max
GENERIC_MAX(float); //相当于定义了一个函数float_max
int main()
{
int r1 = int_max(3, 5);
printf("%dn", r1);
float r2 = float_max(2.3f, 7.6f);
printf("%fn", r2);
return 0;
}
resultado da operação:
Nós também podemos ccg ccggcc Observe os resultados pré-processados no ambiente.i
arquivo, tenha uma compreensão mais intuitiva de
Claro, a função gerada desta forma também é inconveniente para depurar.
Então aqui ##
Que papel isso desempenha?
adicionar ##
, o compilador pensará que eles são um símbolo
Vamos dar uma olhada em Kanga##
Efeito:
De modo geral, a sintaxe para usar funções e macros é muito semelhante, então语言本身没法帮我们区分二者
Um dos nossos hábitos habituais é:
- Nomeie a macrotudo em maiúsculas
- Nome da funçãoNão use todas as letras maiúsculas
Claro, essas regras de nomenclatura não são absolutas
por exemplo deslocamento deslocamentooffsepara Esta macro está escrita em letras minúsculas
Observação: deslocamento deslocamentooffsepara É utilizado para calcular o deslocamento dos membros da estrutura em relação à posição inicial da estrutura.
# indefinido indefinidovocênãoãoãoãoãoãoãoeee As instruções são usadas paraRemover uma definição de macro
O código acima é usado na linha 169# indefinido indefinidovocênãoãoãoãoãoãoãoeee Macro removida MAX.Não há problema ao chamar as 168 linhas antes da remoção, mas um erro será relatado ao chamar as 170 linhas após a remoção.
Muitos compiladores C (não incluindo VS) oferecem a capacidade de definir símbolos na linha de comando.Usado para iniciar o processo de compilação
Por exemplo : Este recurso é útil quando queremos compilar diferentes versões de um programa baseado no mesmo arquivo fonte. (Suponha que um array de um determinado comprimento seja declarado em um programa. Se a memória da máquina for limitada, precisaremos de um array muito pequeno, mas se a memória de outra máquina for maior, o array que precisamos pode ser maior)
A definição da linha de comando está emestágio de pré-processamentoProcessado, na fase de pré-processamento, no código acima tamanho tamanhotamanho O valor de foi determinado
Ao compilar um programa, é muito difícil compilar ou abandonar um (um grupo de instruções).方便
de.porque podemos usardiretiva de compilação condicional
A instrução de compilação condicional é este código我想让你编译就编译,不想让你编译你就不要编译了
. Podemos definir uma condição para ele. Se a condição for verdadeira, este código participará da compilação. Se a condição for falsa, este código não será compilado.
Por exemplo:
Seria uma pena deletar algum código de depuração, mas seria um impedimento para mantê-lo, para que possamos compilá-lo seletivamente.
Instruções de compilação condicional comumente usadas:
#if 常量表达式
//···
#endif
#if 常量表达式
//···
#elif 常量表达式
//···
#else
//···
#endif
Qual afirmação é verdadeira, essa afirmação é executada
#define M 1
int main()
{
#if M == 0
printf("hellon");
#elif M == 1
printf("worldn");
#elif M == 2
printf("csdnn");
#endif
printf("886n");
return 0;
}
#if defined(symbol)
#ifdef symbol
//上面两个的反面
if !defined(symbol)
#ifndef symbol
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
# include "filename"
Estratégia de pesquisa: primeiro emO diretório do projeto onde os arquivos de origem estão localizadosSe o arquivo de cabeçalho não for encontrado, o compilador procurará o arquivo de cabeçalho da função da biblioteca da mesma maneira.Pesquisa de localização padrãoarquivo principal
Se você não conseguir encontrá-lo novamenteErro de compilação
Linux Linuxeuemux O caminho do arquivo de cabeçalho padrão do ambiente (onde o arquivo de cabeçalho é colocado):
/usr/include
Caminho do arquivo de cabeçalho padrão para ambiente VS:
C:Program Files (x86)Microsoft Visual Studio 12.0VCinclude
//这是VS2013的默认路径
#include <filename.h>
Encontre o arquivo de cabeçalho e vá diretamente paracaminho padrãoVá e pesquise e, se não conseguir encontrar, você receberá um aviso.Erro de compilação。
Isso significa que também pode ser usado para arquivos de biblioteca?“ ”
O formulário contém
a resposta éafirmarSim, mas a pesquisa é feita desta formamenos eficiente, claro que este também é o casonão é fácil distinguirÉ um arquivo de biblioteca ou um arquivo local?
Depois de estudar os anteriores (compilação e vinculação), sabemos que a inclusão de arquivos de cabeçalho na etapa de pré-processamento é直接将该文件的代码拷贝到包含头文件的地方
Se um arquivo de cabeçalho for incluído 10 vezes, na verdade será compilado 10 vezes. Se for incluído repetidamente, a pressão na compilação será maior.
teste .c teste.cparaépara.c
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
return 0;
}
teste .h teste.hparaépara.o
void test();
struct Stu
{
int id;
char name[20];
};
Mas em um projeto, um arquivo será inevitavelmente incluído várias vezes, então como resolver esse problema?
Responder:compilação condicional
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
Como entender isso?
- Ao incluir o arquivo de cabeçalho pela primeira vez, ele deve ser compilado?julgar primeiro
- O símbolo __TEST_H__ não énão definido,querercompilar
- Imediatamente depoisDefinir o símbolo __TEST_H__
- Em seguida, inclua o arquivo de cabeçalho novamente e encontre __TEST_H__foi definido,não maisPara o arquivo de cabeçalho incluído posteriormente, executecompilar
No entanto, a forma de escrever acima é mais problemática. Existe outra forma de escrever:
#pragma once
O efeito é o mesmo do método acima
Isso evita a introdução repetida de arquivos de cabeçalho
#error
#pragma
#line
···
#pragma pack()//在结构体部分介绍
Amigos interessados podem ler "Anatomia aprofundada da linguagem C"
Ok, esse é todo o conhecimento sobre pré-processamento nesta edição. Espero que este blog possa ser útil para você. Ao mesmo tempo, corrija-me se houver algum erro e vamos progredir juntos no caminho do aprendizado da linguagem C!