about #pragma

本文介绍了C和C++中#pragma指令,它能指示编译器完成特定动作。详细阐述了#pragma常用参数,如message、code_seg等的作用和用法。还说明了如何通过#pragma pack改变C编译器的字节对齐方式,并以TCP协议首部为例,展示了在网络协议编程中利用结构空间分配原则简化编程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或

者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与

C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器

或操作系统专有的,且对于每个编译器都是不同的。

其格式一般为: #Pragma Para

其中Para 为参数,下面来看一些常用的参数。

 

(1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗

口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:


#Pragma message(“消息文本”)

当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。

当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正

确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自

己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法

#ifdef _X86

#Pragma message(“_X86 macro activated!”)

#endif

当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_

X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了

 

(2)另一个使用得比较多的pragma参数是code_seg。格式如:

#pragma code_seg( [/section-name/[,/section-class/] ] )

它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

 

(3)#pragma once (比较常用)

只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6

中就已经有了,但是考虑到兼容性并没有太多的使用它。

 

(4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预

编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所


以使用这个选项排除一些头文件。

有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#p

ragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据

优先级的大小先后编译。

 

(5)#pragma resource /*.dfm/表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体

外观的定义。

 

(6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )

等价于:

#pragma warning(disable:4507 34) // 不显示4507和34号警告信息

#pragma warning(once:4385) // 4385号警告信息仅报告一次

#pragma warning(error:164) // 把164号警告信息作为一个错误。

同时这个pragma warning 也支持如下格式:

#pragma warning( push [ ,n ] )

#pragma warning( pop )

这里n代表一个警告等级(1---4)。

#pragma warning( push )保存所有警告信息的现有的警告状态。

#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告

等级设定为n。

#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的

一切改动取消。例如:


#pragma warning( push )

#pragma warning( disable : 4705 )

#pragma warning( disable : 4706 )

#pragma warning( disable : 4707 )

//.......

#pragma warning( pop )

在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。

(7)pragma comment(...)

该指令将一个注释记录放入一个对象文件或可执行文件中。

常用的lib关键字,可以帮我们连入一个库文件。

(8)·通过#pragma pack(n)改变C编译器的字节对齐方式
在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

     例如,下面的结构各成员空间分配情况:
struct test
{
     char x1;
     short x2;
     float x3;
     char x4;
};
     结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为12字节。更改C编译器的缺省字节对齐方式
     在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
  · 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
     · 使用伪指令#pragma pack (),取消自定义字节对齐方式。

     另外,还有如下的一种方式:
     · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
     · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见。

应用实例

  在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。下面以TCP协议首部为例,说明如何定义协议结构。其协议结构定义如下:

#pragma pack(1) // 按照1字节方式进行对齐
struct TCPHEADER
{
     short SrcPort; // 16位源端口号
     short DstPort; // 16位目的端口号
     int SerialNo; // 32位序列号
     int AckNo; // 32位确认号
     unsigned char HaderLen : 4; // 4位首部长度
     unsigned char Reserved1 : 4; // 保留6位中的4位
     unsigned char Reserved2 : 2; // 保留6位中的2位
     unsigned char URG : 1;
     unsigned char ACK : 1;
     unsigned char PSH : 1;
     unsigned char RST : 1;
     unsigned char SYN : 1;
     unsigned char FIN : 1;
     short WindowSize; // 16位窗口大小
     short TcpChkSum; // 16位TCP检验和
     short UrgentPointer; // 16位紧急指针
};
#pragma pack() // 取消1字节对齐方式

/* Copyright (c) 2009-2017 Dave Gamble and cJSON contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* cJSON */ /* JSON parser in C. */ /* disable warnings about old C89 functions in MSVC */ #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) #define _CRT_SECURE_NO_DEPRECATE #endif #ifdef __GNUC__ #pragma GCC visibility push(default) #endif #if defined(_MSC_VER) #pragma warning (push) /* disable warning about single line comments in system headers */ #pragma warning (disable : 4001) #endif #include <string.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <float.h> #include <limits.h> #include <ctype.h> #ifdef ENABLE_LOCALES #include <locale.h> #endif #if defined(_MSC_VER) #pragma warning (pop) #endif #ifdef __GNUC__ #pragma GCC visibility pop #endif #include "JSON.h" /* define our own boolean type */ #define true ((cJSON_bool)1) #define false ((cJSON_bool)0) typedef struct { const unsigned char *json; size_t position; }
04-03
优化这段代码,窗口1、3、5、9、11、17、33,输入3200个点,输出也要3200个点,边缘输出原值:#include "SmoothProfileOnXAxisMean.h" #define MAX_WINDOW_SIZE 33 #define HALF_MAX_WINDOW 16 #define II 1 // 每周期处理一个数据 // 使用18位定点数(16位整数 + 8位小数)替代浮点数 typedef ap_fixed<24, 12> fixed_t; typedef ap_fixed<32, 16> fixed_cache; void SmoothProfileOnXAxisMeanOptimize(hls::stream<float>& points_in_z, hls::stream<float>& smoothed_z, ap_uint<6> mean_win_size, float invalid_z ) { #pragma HLS PIPELINE II=1 #pragma HLS INTERFACE ap_ctrl_none port=return #pragma HLS INTERFACE axis port=points_in_z #pragma HLS INTERFACE axis port=smoothed_z #pragma HLS INTERFACE ap_none port=mean_win_size #pragma HLS INTERFACE ap_none port=invalid_z // 循环缓冲区 - 使用定点数提高时序性能 static fixed_t buffer[MAX_WINDOW_SIZE]; #pragma HLS ARRAY_PARTITION variable=buffer complete dim=1 static ap_uint<1> win[MAX_WINDOW_SIZE]; #pragma HLS ARRAY_PARTITION variable=win complete dim=1 static ap_uint<1> invalid_flag0; static ap_uint<1> invalid_flag1; static ap_uint<1> invalid_flag2; // 读取输入并转换为定点数 float in_val_float = points_in_z.read(); fixed_t in_val = in_val_float; fixed_t invalid_z_fixed = invalid_z; // std::cout << "out1_data:" << in_val << " " << invalid_z_fixed << " " << invalid_z <<std::endl; for (int i = MAX_WINDOW_SIZE-1; i > 0; i--){ #pragma HLS UNROLL buffer[i] = buffer[i - 1]; win[i] = win[i-1]; } buffer[0] = (in_val==invalid_z_fixed)?(fixed_t)0:in_val; win[0] = (in_val==invalid_z_fixed)?0:1; static fixed_cache sum_buffer0[11]; static fixed_cache sum_win0[11]; for (int i = 0; i < 11; i=i+1) { #pragma HLS UNROLL sum_buffer0[i] = buffer[i * 3] + buffer[i * 3+1] + buffer[i * 3+2]; sum_win0[i] = win[i * 3] + win[i * 3+1] + win[i * 3+2]; } invalid_flag0 = win[16]; static fixed_cache sum_buffer1[3]; sum_buffer1[0] = sum_buffer0[0] + sum_buffer0[1] + sum_buffer0[2] + sum_buffer0[3]; sum_buffer1[1] = sum_buffer0[4] + sum_buffer0[5] + sum_buffer0[6] + sum_buffer0[7]; sum_buffer1[2] = sum_buffer0[8] + sum_buffer0[9] + sum_buffer0[10]; static fixed_cache sum_win1[3]; sum_win1[0] = sum_win0[0] + sum_win0[1] + sum_win0[2] + sum_win0[3]; sum_win1[1] = sum_win0[4] + sum_win0[5] + sum_win0[6] + sum_win0[7]; sum_win1[2] = sum_win0[8] + sum_win0[9] + sum_win0[10]; invalid_flag1 = invalid_flag0; static fixed_cache sum_buffer2; sum_buffer2 = sum_buffer1[0] + sum_buffer1[1] + sum_buffer1[2]; static fixed_cache sum_win2; sum_win2 = sum_win1[0] + sum_win1[1] + sum_win1[2]; invalid_flag2 = invalid_flag1; // std::cout << "out2_data:" << in_val << " " << sum_buffer2 << " " << sum_win2 <<std::endl; // 除法优化 - 使用移位和乘法避免硬件除法器 fixed_t result; if (invalid_flag2 == 0) { result = invalid_z_fixed; } else { // 使用倒数乘法代替除法 ap_ufixed<24, 8> reciprocal = 1.0 / sum_win2.to_int(); result = fixed_t(sum_buffer2 * reciprocal); } // std::cout << "out2_data:" << in_val << " " << result << " " << sum_buffer2 << " " << sum_win2 << " " << std::endl; smoothed_z.write((float)result); }
最新发布
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值