C语言#pragma使用

article/2025/10/7 1:51:57

1.#pragma简介

(1)#pragma用于指示编译器完成一些特定的动作
(2)#pragma所定义的很多指示字是编译器特有的
(3)#pragma在不同的编译器间是不可移植的
(4)预处理器将忽略它不认识的#pragma指令
(5)不同的编译器可能以不同的方式解释同一条#pragma指令

一般用法︰#pragma parameter

#pragma message

message参数在大多数的编译器中都有相似的实现
message参数在编译时输出消息到编译输出窗口中
message 用于条件编译中可提示代码的版本信息

#error和#warning不同,#pragma message仅仅代表一条编译消息,不代表程序错误。
将下列代码在gcc编译器中运行,查看结果

#include <stdio.h>#if defined(ANDROID20)#pragma message("Compile Android SDK 2.0...")#define VERSION "Android 2.0"
#elif defined(ANDROID23)#pragma message("Compile Android SDK 2.3...")#define VERSION "Android 2.3"
#elif defined(ANDROID40)#pragma message("Compile Android SDK 4.0...")#define VERSION "Android 4.0"
#else#error Compile Version is not provided!
#endifint main()
{printf("%s\n", VERSION);return 0;
}

可以看见,编译的时候,通过#pragma message("Compile Android SDK 2.0...")语句,我们想要的提示信息已经被打印出来了,在不同的编译器对message这个参数处理的结果不一样,在VC和BCC编译器中运行的结果只是打印出了Compile Android SDK 2.0...,与GCC编译器编译的效果有所差异,但差异不大,
在这里插入图片描述

#pragma once

(1)#pragma once 用于保证头文件只被编译一次
(2)#pragma once是编译器相关的,不一定被支持

提出问题:这个方式和#ifndef 、#define、#endif有什么区别?
解释:
#ifndef 、#define、#endif来处理头文件的时候,嵌套处理还是执行了多次的,而#pragma once告诉预编译器只执行一次即可,所以#pragma once的执行效率会比其更高。
虽然#pragma once 的效率更高,但是不同的预编译器对其的支持度不同,所以在很多工程文件中,还是使用#ifndef 、#define、#endif来避免头文件重复包含用的多一点。

示例代码

#include <stdio.h>
#include "global.h"
#include "global.h"int main()
{printf("g_value = %d\n", g_value);return 0;
}

global.h


#pragma onceint g_value = 1;

在gcc进行编译,结果正常运行,原因就在于在头文件中已经使用#pragma once 进行了声明该头文件只被包含一次。
在bcc编译器进行编译,会报错,这款编译器不支持#pragma once ,被忽略了,所以头文件被包含了两次。
所以有一种推荐写法:即将#pragma once写在在中间部分

#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#pragma once int g_value = 1;#endif

pragma pack

保证内存对齐,什么是内存对齐?
-----不同类型的数据在内存中按照一定的规则排列,而不一定是顺序的一个接一个的排列。

为什么需要内存对齐?
(1)CPU对内存的读取不是连续的,而是分成块读取的,块的大小只能是1、2、4、8、16…字节
(2)当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
(3)某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常(如STM32单片机)

#pragma pack 用于指定内存对齐方式

看下面的结构体,想想输出的结果是什么呢?

#include <stdio.h>struct Test1
{char  c1;short s;char  c2;int   i; 
};struct Test2
{char  c1;char  c2;short s;int   i;
};int main()
{printf("sizeof(Test1) = %d\n", sizeof(struct Test1));printf("sizeof(Test2) = %d\n", sizeof(struct Test2));return 0;
}

分别是12和8
在这里插入图片描述
内存空间的存储方式是这样的。
在这里插入图片描述
结构体计算要遵循字节对齐原则,结构体大小结果要为成员中最大字节的整数倍,编译器在默认情况下是是4字节对齐的。参考文章:结构体字节对齐

struct占用的内存大小,重要的几点在下面列出:(务必掌握)
1.第一个成员起始于0偏移处
2.每个成员按其类型大小和pack参数中较小的一个进行对齐
3.偏移地址必须能被对齐参数整除(坑人)
4.结构体成员的大小取其内部长度最大的数据成员作为其大小
5.结构体总长度必须为所有对齐参数的整数倍(这个最重要)

Test1结构体中,

				 对齐参数   偏移地址  大小
char  c1;          1          0     1
short s;           2          2     2
char  c2;          1          4     1
int   i;           4          8     4

对于short s对齐参数是2,偏移地址必须是对齐参数的整数倍,那么偏移位置不能是1了,只能是2。
同理,int i对齐参数是4,偏移地址起始地址不能是5了,因为要满足对齐参数的整数倍,只能是8才行。那么最后一个变量i的偏移地址是8,大小是4,所以8+4=12,且12是所有对齐参数的整数倍,该结构体的大小就为12个字节了。我们的分析与上图的示意图是一致的。

Test2结构体中,

				 对齐参数   偏移地址  大小
char  c1;          1          0     1
char  c2;          1          1     1
short s;           2          2     2
int   i;           4          4     4

最后一个变量i的偏移地址是4,大小是4,所以4+4=8,且8是所有对齐参数的整数倍,该结构体的大小就为8个字节了。

编译器默认4字节对齐的意思就是,下面的代码和没有加#pragma pack(4)、#pragma pack()组合算出来结构体的大小结果是一样的。

#pragma pack(4)
struct Test1
{char  c1;short s;char  c2;int   i; 
};
#pragma pack()#pragma pack(4)
struct Test2
{char  c1;char  c2;short s;int   i;
};
#pragma pack()

训练一下,
例子1

#include <stdio.h>#pragma pack(2)
struct Test1
{				//对齐参数   偏移地址  大小char  c1;	// 1 	     0       1short s;    // 2         2       2char  c2;  //  1	     4       1int   i;   //  4		 6       4
};
#pragma pack()#pragma pack(4)
struct Test2
{				//对齐参数   偏移地址  大小						char  c1;//   1          0       1char  c2;//   1		     1       1short s;//    2          2       2int   i;//    4          4       4
};
#pragma pack()int main()
{printf("sizeof(Test1) = %d\n", sizeof(struct Test1));printf("sizeof(Test2) = %d\n", sizeof(struct Test2));return 0;
}
结果是108

例子2

#include <stdio.h>#pragma pack(8)struct S1
{				//对齐参数   偏移地址  大小	short a;  //  2          0        2long b;   //  4          4        4
};struct S2
{			   //对齐参数   偏移地址  大小	char c;//      1        0       1struct S1 d;// 4        4       8double e;//    8        16      8
};#pragma pack()int main()
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0;
}

不同编译器处理的结果是不同的,gcc编译器不支持八字节对齐,double的对齐参数只能为4计算,所以得到结构体2的大小为20,但是在BCC编译器大小就为24了。

2.小结

(1)#pragma用于指示编译器完成一些特定的动作
(2)#pragma所定义的很多指示字是编译器特有的
(3)#pragma message 用于自定义编译消息
(4)#pragma once 用于保证头文件只被编译一次
(5)#pragma pack 用于指定内存对齐方式


http://chatgpt.dhexx.cn/article/3HbW2ybl.shtml

相关文章

C语言#pragma使用方法

C语言#pragma使用方法 一、总结 1、#pragma用于指示编译器完成一些特定的动作 2、#pragma所定义的很多指示字是编译器特有的(每种编译可能都不一样) &#xff08;1&#xff09; #pragma message 用于自定义编译信息 &#xff08;2&#xff09;#pragma once 用于保证头文件只被…

pragma是什么意思?(词源强迫症患者的无聊问题

------此处的pragma仅指各类编程语言中的预处理指令#pragma------ 作为一位词源强迫症患者&#xff0c;为了我自己&#xff08;以免遗忘&#xff09;和广大病友们&#xff0c;我将找到的一些信息源在此记录如下&#xff1a; ---中文信息 “#Pragma是预处理指令它的作用是设定编…

#pragma的常用方法讲解

概述 我们在写代码时&#xff0c;总会遇到头文件多次包含的情况&#xff0c;刚开始时我们使用宏定义进行控制&#xff0c;之后发现有#pragma once这样简单的东西&#xff0c;当时是很兴奋&#xff0c;以为#pragma就这一种用法。唉~&#xff0c;现在想想当时还是年轻啊&#xf…

Attribute(特性)

一向都觉得.NET的Attribute好神秘。一个方框框住的东西&#xff0c;置身于类、方法的头部&#xff0c;本身不在类或方法里面&#xff0c;但又会起作用&#xff0c;有时作用还很大&#xff0c;仿佛充满了魔力。简直给人一种无冕之王&#xff0c;幕后之黑手的感觉&#xff01; 某…

attribute的用法--C#

一直以来都没理解attribute是个什么东西&#xff0c;也没怎么用&#xff0c;但是看msdn或者git上源码使用的还是蛮频繁的&#xff0c;今天好好整理了下&#xff0c;写下自己的理解和例子&#xff1a; attribute主要用来说明代码段的的信息&#xff0c;标志等&#xff1b;可以一…

attribute属性

attribute属性 __attribute__介绍 attribute的格式. __attribute__((attribute-list))attribute属性可以在编译的时候告诉编译器函数, 结构体的属性是什么, 进行某些编译优化, 也可以提供更加准确的错误检查. attribute是GNU特有的特性 这里主要说明attribute的4个属性, 分…

【C#】Attribute

原文链接&#xff1a;http://bbs.51aspx.com/showtopic-33963.html 前言 作为一个.NET开发人员&#xff0c;了解Attribute的重要性&#xff0c;用.NET大师Jeffrey Richter的话就是“任何.NET Framework 开发人员都有必要对定制attribute有一个牢靠的掌握”&#xff0c;所以掌…

attributes() 函数

查看更多 https://www.yuque.com/docs/share/a6cc2c96-9824-4903-acb8-284f4ebeb4fb

__attribute__ 用法

转自&#xff1a;http://www.cnblogs.com/astwish/p/3460618.html GNU C 的一大特色就是__attribute__ 机制。__attribute__ 可以设置函数属性&#xff08;Function Attribute &#xff09;、变量属性&#xff08;Variable Attribute &#xff09;和类型属性&#xff08;Type …

View绘制体系(三)——AttributeSet与TypedArray详解

View绘制体系&#xff08;三&#xff09;——AttributeSet与TypedArray详解 前言 上篇博客中讲了LayoutInflater.inflate机制&#xff0c;其中提到了AttributeSet和XmlPullParser两个接口&#xff0c;这里我们来详细的了解一下Android中提供的AttributeSet接口和它与XmlPullPa…

Android自定义View(三)自定义属性AttributeSet

自定义View的时候通常需要提供一些自定义属性&#xff0c;自定义属性非常简单&#xff0c;只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件&#xff0c;然后在该文件中定义相应的属性&#xff0c;并在自定义View的构造函数中获取并设置自定义属性的默认值即…

web搜索框的制作(必应)

前两天没事突然对搜索来了兴趣&#xff0c;我一直在想搜索框中我们输入一些字或者字母&#xff0c;为何下面就会有一些自动补齐的相关搜索&#xff0c;比如我在搜索输入框中输入一个字母e&#xff0c;下面就会出现饿了么&#xff0c;e租宝&#xff0c;ems等相关的搜索链接。然后…

html怎么调搜索框宽高,百度站内搜索css:输入框宽度及样式自定义

近日网站使用了百度站内搜索api&#xff0c;目的是为了提高站内搜索的速度&#xff0c;减轻查询站内数据库带来的服务器压力。 不过在使用百度站内搜索api(生效范围&#xff1a;*webkaka.com/*)后发现一个问题&#xff0c;不同的频道模版造成排版不合适的后果&#xff0c;如搜索…

织梦手机站站内搜索

今天在做手机网站发现一个问题&#xff0c;当在手机是使用搜索功能时马上就跳转到电脑端网站去了&#xff0c;在手机上无法使用。在网上找半天没有找到解决的办法&#xff0c;后来自己想通了&#xff0c;下面告诉大家怎么样简单的实现这个功能&#xff01;我的手机站是在m/这个…

基于 Elasticsearch 的站内搜索引擎实战

站内搜索&#xff0c;可以认为是针对一个网站特性内容的搜索功能。由于内容、格式可控&#xff0c;站内搜索比全网搜索的实现要简单很多。 简书这个网站本身自带一个搜索&#xff0c;但是缺乏针对个人文章的搜索&#xff0c;所以本文的实战内容是解决这个痛点。 代码在 https…

使用swiftype实现站内搜索

本人博客opiece.me&#xff0c;欢迎访问。 前言 首先&#xff0c;以下的内容是基于最新的swifytpe的教程&#xff0c;应该是2.0.0。 站内搜索顾名思义就是将范围限定在你的网站内&#xff0c;以此范围进行关键字搜索。 常见的站内搜索是google和baidu的&#xff0c;但是现在…

Compass实战 站内搜索

今天早上打算对这两天学习的Lucene以及Compass总结一下,想来想去,还是写个小项目来验证最好了。于是就有了今天的这篇文章。难易程度适合对于Compass或者Lucene刚入门的童鞋,大牛看到后望轻喷 :-) 项目预览项目需求项目目录核心处理 发帖部分查询部分总结项目预览 项目需求 …

html中的搜索

目录 hello&#x1f604; form表单&#x1f349; form的语法&#x1f34a; from的属性&#x1f34a; 提交&#xff1f;重置&#xff1f;&#x1f34a; 表单按钮&#xff08;html&#xff09;&#x1f50d; JavaScript提交表单&#x1f50d; JavaScript重置表单&#x1f…

必应(Bing)的站内搜索 site:<域名> <搜索内容>

最近在备考OCP&#xff0c;发现有一个网站的题库很好&#xff0c;就是www.examtopics.com&#xff0c;有很多Oracle的考题&#xff0c;都是在这里面搜到的&#xff0c;而且每道题都有人讨论。 为了加快搜索速度&#xff0c;提高精度&#xff0c;可以用Bing在这个网站内搜索&am…

百度站内搜索使用教程

最近做了一个博客CMS网站&#xff0c;用到了百度站内搜索&#xff0c;做一些必要的笔记&#xff0c;一来是对自己学习的知识的巩固&#xff0c;二来对有同样问题的人有参考作用 文章目录 一 使自己的网站被百度收录二 获取百度站内搜索代码三 总结 声明一下&#xff0c;我本人很…