Uso de #pragma em C


117

Quais são alguns usos de #pragmaem C, com exemplos?


2
#pragmaA diretiva sobrevive ao estágio de pré-processamento. Ao contrário de #includee #define.
smwikipedia


@smwikipedia, você quer dizer que alguns pragmas sobrevivem? #pragma once é uma diretiva de pré-processador, mas #pragma pack é uma diretiva de compilador
Lewis Kelsey

Respostas:


66

#pragma é para diretivas de compilador que são específicas da máquina ou do sistema operacional, ou seja, diz ao compilador para fazer algo, definir alguma opção, executar alguma ação, substituir algum padrão, etc. que pode ou não se aplicar a todas as máquinas e operação sistemas.

Veja msdn para mais informações.


11
"isso pode ou não se aplicar a todas as máquinas e sistemas operacionais." - e diferentes compiladores na mesma máquina. E o que pode significar coisas diferentes em compiladores diferentes.
Steve Jessop,

53

#pragma é usado para fazer algo específico de implementação em C, ou seja, ser pragmático para o contexto atual ao invés de ideologicamente dogmático.

O que eu uso regularmente é #pragma pack(1)onde estou tentando espremer mais do meu espaço de memória em soluções incorporadas, com matrizes de estruturas que, de outra forma, terminariam com alinhamento de 8 bytes.

Pena que ainda não temos #dogma. Isso seria divertido ;)


@ShaneMacLaughlin, Na verdade também não pragma(1)melhora a velocidade? Consulte stackoverflow.com/questions/3318410/…
Pacerier

4
@Pacerier, normalmente não. De acordo com os comentários do jalfs, os dados alinhados em um limite de 4 bytes para processadores de 32 bits ou de 8 bytes para processadores de 64 bits serão normalmente carregados e armazenados em uma única operação. Os dados alinhados em limites menores exigirão várias operações para carregar ou armazenar. Isso é mais lento.
SmacL de

35

Eu geralmente tentaria evitar o uso de #pragmas, se possível, já que eles são extremamente dependentes do compilador e não portáteis. Se você quiser usá-los de forma portátil, terá que envolver cada pragma com um par #if/ #endif. O GCC desencoraja o uso de pragmas e realmente só oferece suporte a alguns deles para compatibilidade com outros compiladores; O GCC tem outras maneiras de fazer as mesmas coisas para as quais outros compiladores usam pragmas.

Por exemplo, veja como você pode garantir que uma estrutura seja compactada firmemente (ou seja, sem preenchimento entre os membros) no MSVC:

#pragma pack(push, 1)
struct PackedStructure
{
  char a;
  int b;
  short c;
};
#pragma pack(pop)
// sizeof(PackedStructure) == 7

Veja como você faria a mesma coisa no GCC:

struct PackedStructure __attribute__((__packed__))
{
  char a;
  int b;
  short c;
};
// sizeof(PackedStructure == 7)

O código GCC é mais portátil, porque se você quiser compilá-lo com um compilador não-GCC, tudo que você precisa fazer é

#define __attribute__(x)

Ao passo que, se você deseja portar o código MSVC, deve envolver cada pragma com um par #if/ #endif. Feio.


3
Portanto, se eu quiser compilar o código GCC no MSVC e precisar compactar a estrutura, exatamente como faço?
SmacL

2
Para gcc, é struct __attribute__((__packed__)) PackedStructure
Laurent Debricon

#pragma uma vez não é realisticamente "dependente do compilador e não portátil". É suportado em todas as principais plataformas e muitos não-principais plataformas .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
Observe que C99 e C11 contêm (C11) §6.10.6 diretivas Pragma e ¶1 Qualquer pragma que não seja reconhecido pela implementação é ignorado. Até mesmo C90 diz isso, embora estivesse na seção §6.8.6. (Isso torna o GCC não compatível se for executado hackao encontrar um pragma que não reconhece, como costumava fazer há muito, muito tempo - veja #pragmae GCC , etc.)
Jonathan Leffler

15

Colocar #pragma onceno topo do arquivo de cabeçalho garantirá que ele seja incluído apenas uma vez. Observe que #pragma oncenão é o C99 padrão, mas é compatível com a maioria dos compiladores modernos.

Uma alternativa é usar proteções de inclusão (por exemplo #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

o que eu sinto é #pragmauma diretiva onde se você quiser que o código seja específico de um local. diga uma situação em que você deseja que o contador do programa leia do endereço específico onde o ISR está escrito, então você pode especificar o ISR naquele local usando #pragma vector=ADC12_VECTORe seguido por nome de rotinas de interrupção e sua descrição


5

Meu melhor conselho é examinar a documentação do seu compilador, porque os pragmas são, por definição, específicos da implementação. Por exemplo, em projetos incorporados, usei-os para localizar código e dados em diferentes seções ou declarar manipuladores de interrupção. ie:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
Todos os pragmas são específicos de implementação - exceto os pragmas #pragma STDC ..., que são padronizados em todas as plataformas (além do C99).
Jonathan Leffler

4

Todas as respostas acima são boas explicações para, #pragmamas eu queria adicionar um pequeno exemplo

Eu só quero explicar um simple OpenMP exampleque demonstra alguns usos de #pragmafazer seu trabalho

OpenMp brieflyé uma implementação para programação paralela de memória compartilhada multiplataforma (então podemos dizer que é machine-specificou operating-system-specific)

vamos ao exemplo

#include <stdio.h>
#include <omp.h>// compile with: /openmp

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}

a saída é

Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

Note that the order of output can vary on different machines.

agora deixe-me dizer o que #pragmafez ...

diz ao sistema operacional para executar algum bloco de código em 4 threads

isso é apenas um de many many applicationsvocês pode fazer com o pouco#pragma

desculpe pela amostra externa OpenMP


3

Esta é uma diretiva de pré-processador que pode ser usada para ligar ou desligar certos recursos.

É de dois tipos #pragma startup, #pragma exite #pragma warn.

#pragma startup nos permite especificar funções chamadas na inicialização do programa.

#pragma exit nos permite especificar funções chamadas na saída do programa.

#pragma warn diz ao computador para suprimir qualquer aviso ou não.

Muitos outros #pragmaestilos podem ser usados ​​para controlar o compilador.


3

#pragma startup é uma diretiva que é usada para chamar uma função antes da função principal e para chamar outra função após a função principal, por exemplo

#pragma startup func1
#pragma exit func2

Aqui, func1corre antes maine func2corre depois.

NOTA: Este código funciona apenas no compilador Turbo-C. Para obter essa funcionalidade no GCC, você pode declarar func1e func2assim:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();

2

Para resumir, #pragmadiz ao compilador para fazer as coisas. Aqui estão algumas maneiras de usá-lo:

  • #pragmapode ser usado para ignorar avisos do compilador. Por exemplo, para fazer o GCC calar a boca sobre declarações de funções implícitas, você pode escrever:

    #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"

    Uma versão mais antiga do libportablefaz isso portavelmente .

  • #pragma once, quando escrito no topo de um arquivo de cabeçalho, fará com que o referido arquivo de cabeçalho seja incluído uma vez. libportable verifica o pragma uma vez que o suporte.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.