Expressão avançada de instruções do Linux

Expressão

Expressões e declarações são os conceitos básicos na linguagem C. O que é uma expressão? Uma expressão é uma fórmula composta por uma série de operadores e operandos. Os operadores podem ser vários operadores aritméticos, operadores lógicos, operadores de atribuição, operadores de comparação, etc. especificados pelo padrão da linguagem C. O operando pode ser uma constante ou uma variável. As expressões também não podem ter operadores.Uma constante única ou mesmo uma string também é uma expressão. As seguintes seqüências de caracteres são todas expressões:

  • 2 + 3
  • 2
  • i = 2 + 3
  • i = i ++ + 3
  • "sagacidade"

Expressões são geralmente usadas para cálculos de dados ou algoritmos que implementam uma determinada função. As expressões têm 2 atributos básicos: valor e tipo. Como a expressão acima 2 + 3, seu valor é 5. De acordo com diferentes operadores, as expressões podem ser divididas em vários tipos, como:

  • Expressão relacional
  • Expressão lógica
  • Expressão condicional
  • Expressão de atribuição
  • Expressão aritmética
  • ……

Declaração

As declarações são a unidade básica de um programa.A forma geral é a seguinte:

表达式 ;
i = 2 + 3 ;

Adicione um após a expressão, que constitui uma declaração básica. Quando o compilador compila e analisa o programa, ele não se baseia na linha física, mas no ponto e vírgula; para determinar a marca final de uma instrução. Como i = 2 + 3; esta declaração, você também pode compilar através do seguinte formulário:

i =
2 + 
3
;

Bloco de código

Instruções diferentes, entre colchetes {}, constituem um bloco de código. A linguagem C permite definir uma variável em um bloco de código, e o escopo dessa variável também é limitado a esse bloco de código, porque o compilador gerencia o escopo da variável com base no {} para executar operações de pilha. Como o seguinte procedimento:

int main(void)
{
    int i = 3; 
    printf("i=%d\n",i);
    {
        int i = 4;
        printf("i=%d\n",i);
    }
    printf("i=%d\n",i);
    return 0;
}
运行结果为:
i=3
i=4
i=3

Expressão de declaração

Definição de expressão de declaração

O GNU C estende o padrão C para permitir que instruções sejam incorporadas em uma expressão, permitindo que variáveis ​​locais, para loops, e instruções goto jump nas expressões. Tais expressões são chamadas de expressões de instrução . O formato da expressão da instrução é o seguinte:

({ 表达式1; 表达式2; 表达式3; })

O mais externo da expressão de instrução está entre parênteses () . Dentro do par de colchetes {} está o bloco de código , que permite que várias instruções sejam incorporadas. O formato da instrução pode ser "expressão;" Esta é uma instrução de formato geral ou pode ser uma instrução como um loop ou um salto.

Como expressões regulares, expressões de instrução têm seus próprios valores. O valor da expressão da instrução é o valor da última expressão na instrução incorporada . Vamos dar um exemplo, usando expressões de instrução para avaliar.

int main(void)
{
    int sum = 0;
    sum = 
    ({
        int s = 0;
        for( int i = 0; i < 10; i++)
            s = s + i;
            s;
    });
    printf("sum = %d\n",sum);
    return 0;
}

No programa acima, o somatório cumulativo de 1 a 10 é realizado pela expressão de instrução, porque o valor da expressão de instrução é igual ao valor da última expressão, portanto, após o loop for, queremos adicionar uma representação de instrução s; O valor de toda a expressão da instrução. Se você não adicionar esta frase, encontrará sum = 0. Ou você pode alterar essa instrução para 100. Você descobrirá que o valor da última soma se torna 100, porque o valor da expressão da instrução é sempre igual ao valor da última expressão.

Use goto para pular dentro das expressões de instrução

No programa acima, definimos variáveis ​​locais na expressão da instrução e usamos uma instrução for loop. Na expressão de declaração, também podemos usar goto para pular.

int main(void)
{
    int sum = 0;
    sum = 
    ({
        int s = 0;
        for( int i = 0; i < 10; i++)
            s = s + i;
            goto here;
            s;  
    });
    printf("sum = %d\n",sum);
here:
    printf("here:\n");
    printf("sum = %d\n",sum);
    return 0;
}

Use expressões de instrução em definições de macro

O destaque das expressões de instrução são as macros que definem funções complexas. O uso de expressões de instrução para definir macros pode não apenas alcançar funções complexas, mas também evitar ambigüidades e brechas causadas por definições de macro. A seguir, é apresentado um exemplo de definição de macro. Vamos ver a poderosa letalidade da expressão de sentença na definição de macro!

Se você está entrevistando no momento, a posição da entrevista é: Engenheiro de desenvolvimento de linguagem Linux C. O entrevistador tem uma pergunta para você:

Defina uma macro para encontrar o máximo de dois números .

Não olhe para uma pergunta de teste tão simples, o entrevistador pode julgar suas habilidades no idioma C com base na macro que você escreve e decidir se deseja fazer uma oferta.

Qualificado

Para os alunos que aprenderam a linguagem C, escrever essa macro não é difícil e pode ser feito usando operadores condicionais:

#define  MAX(x,y)  x > y ? x : y

Essa é a gramática mais básica da linguagem C. Se você não conseguir escrever isso, estima-se que a cena será mais complicada. Para facilitar o constrangimento, o entrevistador geralmente diz para você: rapaz, você é ótimo, volte e espere as notícias.Nós o informaremos quando houver novidades! Neste momento, você deve entender: não espere mais, leia este artigo rapidamente e depois vá para casa. Essa macro pode ser escrita e você não se considera um bom X, porque isso mostra apenas que você tem a base da linguagem C, mas ainda há muito espaço para melhorias. Por exemplo, vamos escrever um programa para verificar se a macro que definimos está correta:

#define MAX(x,y) x > y ? x : y
int main(void)
{
    printf("max=%d",MAX(1,2));
    printf("max=%d",MAX(2,1));
    printf("max=%d",MAX(2,2));
    printf("max=%d",MAX(1!=1,1!=2));
    return 0;
}

Testar o programa? Devemos testar todas as situações possíveis. Não, teste a instrução na linha 4. Quando o parâmetro da macro é uma expressão, verifica-se que o resultado real da execução é max = 0, que é diferente do resultado esperado max = 1. Isso ocorre porque, depois que a macro é expandida, fica assim:

printf("max=%d",1!=1>1!=2?1!=1:1!=2);

Como o operador de comparação> tem uma prioridade 6, que é maior que! = (A prioridade é 7), a ordem das operações na expressão expandida muda e o resultado não é o que esperávamos. Para evitar esse erro de expansão, podemos adicionar parênteses () aos parâmetros da macro para impedir que a ordem de operação da expressão seja alterada após a expansão. Somente essa macro pode ser considerada uma macro qualificada:

#define MAX(x,y) (x) > (y) ? (x) : (y)

Médio

A macro acima só pode ser considerada qualificada, mas ainda existem brechas. Por exemplo, usamos o seguinte código para testar:

#define MAX(x,y) (x) > (y) ? (x) : (y)
int main(void)
{
    printf("max=%d",3 + MAX(1,2));
    return 0;
}

No programa, imprimimos o valor da expressão 3 + MAX (1, ​​2) O resultado esperado deve ser 5, mas o resultado real de execução é 1. Depois que começamos, descobrimos que também havia problemas:

3 + (1) > (2) ? (1) : (2);

Como o operador + tem uma prioridade mais alta que o operador de comparação>, essa expressão se torna 4> 2? 1: 2 e acontece que o resultado é 1 não é surpreendente. Neste ponto, devemos continuar a modificar esta macro:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

Use parênteses para quebrar a definição da macro, para que quando uma expressão contiver a definição da macro e outros operadores de alta prioridade, a ordem de cálculo de toda a expressão seja destruída. Se você pode escrever esta etapa, isso significa que você é melhor do que o ex-aluno que passou na entrevista.O ex-aluno voltou a aguardar as notícias e, em seguida, a entrevista para a próxima rodada.

Bom

Embora a macro acima resolva os problemas causados ​​pela precedência do operador, ainda existem algumas brechas. Por exemplo, usamos o seguinte programa de teste para testar a macro que definimos:

#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%d",MAX(i++,j++));
    return 0;
}

No programa, definimos duas variáveis ​​iej, e depois comparamos o tamanho das duas variáveis ​​e fazemos a operação de incremento. Os resultados reais da operação descobriram que max = 7, em vez do resultado esperado max = 6. Isso ocorre porque as variáveis ​​iej foram incrementadas duas vezes após a expansão da macro, resultando no valor i sendo impresso como 7.

Nesse caso, o que devo fazer? Neste momento, a expressão de declaração deve entrar no palco. Podemos usar expressões de instrução para definir essa macro e definir duas variáveis ​​temporárias nas expressões de instrução para armazenar temporariamente os valores de iej e depois compará-los, para evitar o problema de dois incrementos e decréscimos.

#define MAX(x,y)({     \
    int _x = x;        \
    int _y = y;        \
    _x > _y ? _x : _y; \
})
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%d",MAX(i++,j++));
    return 0;
}

Expressão na instrução, definimos duas variáveis locais  _x, _y para armazenar o valor dos parâmetros macro X e Y, em seguida, para comparar o tamanho e _y _x, evitando assim trazer i e j incremento operador 2 Problema.

Você pode manter esse nível e escrever uma macro com a BGM, o entrevistador já pode ter a intenção de oferecer uma oferta. Mas neste momento, não tenha orgulho! Para dissipar completamente as preocupações psicológicas do entrevistador, precisamos continuar a otimizar essa macro.

Excelente

Na macro acima, os tipos de dados das duas variáveis ​​temporárias que definimos são int e só podemos comparar os dados de dois tipos inteiros. Para outros tipos de dados, você precisa redefinir uma macro, o que é um problema demais! Podemos continuar a modificar com base na macro acima, para suportar qualquer tipo de tamanho de comparação de dados:

#define MAX(type,x,y)({     \
    type _x = x;        \
    type _y = y;        \
    _x > _y ? _x : _y; \
})
int main(void)
{
    int i = 2;
    int j = 6;
    printf("max=%d\n",MAX(int,i++,j++));
    printf("max=%f\n",MAX(float,3.14,3.15));
    return 0;
}

Nesta macro, adicionamos um parâmetro: type, usado para especificar os tipos de variáveis ​​temporárias _x e _y. Dessa forma, quando comparamos o tamanho de dois números, desde que os dois tipos de dados sejam passados ​​como parâmetros para a macro, podemos comparar qualquer tipo de dado. Se você conseguir escrever uma macro assim na entrevista, o entrevistador ficará muito feliz e geralmente lhe dirá: Espere um momento, o RH conversará com você sobre o tratamento mais tarde. Parabéns, você recebeu a Oferta!

Uso de expressões de instrução no kernel do Linux

Expressões de instrução, como uma extensão do GNU C ao padrão C, são amplamente usadas no kernel, especialmente na definição de macro do kernel. O uso de expressões de instrução para definir macros pode não apenas alcançar funções complexas, mas também evitar algumas ambiguidades e vulnerabilidades causadas pelas definições de macro. Por exemplo, no kernel do Linux, max_t e as min_t definições de macro usam expressões de instrução:

#define min_t(type, x, y) ({            \
    type __min1 = (x);          \
    type __min2 = (y);          \
    __min1 < __min2 ? __min1 : __min2; })

#define max_t(type, x, y) ({            \
    type __max1 = (x);          \
    type __max2 = (y);          \
    __max1 > __max2 ? __max1 : __max2; })

Além disso, no kernel do Linux e no software de código aberto GNU, você encontrará que um grande número de definições de macro usa expressões de instrução. Através do estudo deste tutorial, acredito que todos encontrarão esse tipo de macro definido por expressões de declaração no futuro e saberão definitivamente o que está acontecendo.

发布了81 篇原创文章 · 获赞 69 · 访问量 5万+

Acho que você gosta

Origin blog.csdn.net/s2603898260/article/details/103657829
Recomendado
Clasificación