精华内容
下载资源
问答
  • 本程序为再c语言中嵌入汇编语言#pragma,c语言和汇编语言各有优势,两种语言相互嵌入可以取长补短,优势互补。
  • 前言 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定...此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。 看测试代码:(说明,64位GCC,默认8字节对齐) 屏蔽了的代...

    前言

    我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。
    但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢?
    此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。
    看测试代码:(说明,64位GCC,默认8字节对齐)
    在这里插入图片描述
    屏蔽了的代码先别看,只看这个结构体,在默认8字节对齐的方式下,sizeof大小为24个字节,这不再做分析,之前随笔分析过了。

    pragma pack()

    然后我加上强制4字节对齐之后:
    在这里插入图片描述
    那么现在,我再新建一个结构体B,内容和结构体C一样,只是对齐方式向分别采取不同的方式:

    #include <stdio.h>
    
    #pragma   pack(4) 
    struct C {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack() 
    struct B {
        double d;
        char b;
        int a;
        short c;
    };

    像上面那样处理之后,输出:先打印结构C,再打印结构B
    在这里插入图片描述
    这说明了,在强制4字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。
    #pragma pack() 能够取消自定义的对齐方式,恢复默认对齐。

    pragma(pop) & pragma pack(push)

    继续测试:

    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };

    输出:
    在这里插入图片描述
    好像没什么作用的感觉,那么再加上一个#pragma pack(push)试试呢?

    #include <stdio.h>
    
    #pragma pack(push) 
    #pragma   pack(4) 
    
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    
    #pragma pack(pop) 
    
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n",sizeof(struct CC),sizeof(struct BB));
        return 0;
    }

    在这里插入图片描述
    这样似乎改变了,有不同的地方体现了出来。
    #pragma pack(push):
    英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
    #pragma pack(pop):
    英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。
    push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。
    这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;
    也可以使用:

    #pragma pack(push)
    #pragma pack(4)
    struct...
    #pragma pack(pop)

    这样在push和pop之间的结构体就可以按照pack指定的字节(这里是4字节对齐方式),而pop之后的结构体按照#pragma pack(push) 前对齐方式。
    eg:

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop)
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    在这里插入图片描述
    先按照2字节对齐,然后push保存2字节对齐,然后又强制4字节对齐,打印CC为20字节,然后强制1字节对齐,打印BB为15字节,然后pop,pop会让编译器回到push之前的对齐方式(这里是2字节对齐),打印AA(按照2字节对齐)16字节。
    注意,#pragma pack() 取消自定义对齐方式,恢复默认方式,而push之后pop是回到push指令之前的对齐方式。
    eg:

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack()
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    只把pop改成pack()打印如下:
    在这里插入图片描述
    最后回到的不是2字节对齐,而是默认的8字节对齐。

    延伸

    还有延伸点:
    在这里插入图片描述
    上图红色处等价于它下面的两句。

    语法:

    #pragma pack( [show] | [push | pop] [, identifier], n )

    说明:
    1,pack提供数据声明级别的控制,对定义不起作用;
    2,调用pack时不指定参数,n将被设成默认值;
    3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;

    语法具体分析:
    1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;
    2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;
    3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;
    4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;
    5,n:可选参数;指定packing的数值,以字节为单位;

    另外:

    __attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
    __attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐

    参考

    参考原文:https://www.cnblogs.com/yangguang-it/p/7392726.html

    展开全文
  • 下面小编就为大家带来一篇全面了解#pragma once与 #ifndef的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • C语言_#pragma用法详解

    2014-04-08 20:40:54
    #pragma 指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的, 且对于每个编译器都是不同的。
  • 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。 但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢? 此时,#pragma pack(push) 和...

    我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。

    但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢?

    此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。

    #include <stdio.h>
    
    #pragma   pack(4) 
    struct C {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack() 
    struct B {
        double d;
        char b;
        int a;
        short c;
    };
    

    这说明了,在强制4字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。

    #pragma pack() 能够取消自定义的对齐方式,恢复默认对齐。

    #include <stdio.h>
    
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n",sizeof(struct CC),sizeof(struct BB));
        return 0;
    }
    

    #pragma pack(push):

    英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。

    #pragma pack(pop):

    英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。

    push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。

    这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;

    也可以使用:

    #pragma pack(push)
    #pragma pack(4)

    struct。。。

    #pragma pack(pop)

    这样在push和pop之间的结构体就可以按照pack指定的字节(这里是4字节对齐方式),而pop之后的结构体按照#pragma pack(push) 前对齐方式。

    展开全文
  • C++中#include、#pragma的含义
  • C++ #pragma 预处理指令详解 魔鬼作坊学游戏辅助制作 moguizuofang.com
  • #pragma //提供额外信息的标准方法,可用于指定平台。 这个标记其实是很复杂的,它是什么特点呢,它是根据你的编译平台,就是根据你所用的不同的编译器然后你再不同的环境下,它可以有不同的表达,它能干好多不同的...
  • #pragma comment ( lib,"wpcap.lib" ) 表示链接wpcap.lib这个库。和在工程设置里写上链入wpcap.lib的效果一样(两种方式等价,或说一个隐式一个显式调用),不过这种方法写的 程序别人在使用你的代码的时候就不用...
    #pragma comment ( lib,"wpcap.lib" )  
    

    表示链接wpcap.lib这个库。和在工程设置里写上链入wpcap.lib的效果一样(两种方式等价,或说一个隐式一个显式调用),不过这种方法写的 程序别人在使用你的代码的时候就不用再设置工程settings了。告诉连接器连接的时候要找ws2_32.lib,这样你就不用在linker的lib设置里指定这个lib了。

    比如:

    #include "Mwic_32.h"  
    #pragma comment(lib,"Mwic_32.lib")  
    

    就不需要在project setting里面设置了
    #pragma comment( comment-type [,“commentstring”] )
    该宏放置一个注释到对象文件或者可执行文件。
    comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。
    commentstring是一个提供为comment-type提供附加信息的字符串,
    Remarks:
    1、compiler:放置编译器的版本或者名字到一个对象文件,该选项是被linker忽略的。
    2、exestr:在以后的版本将被取消。
    3、lib:放置一个库搜索记录到对象文件中,这个类型应该是和commentstring(指定你要Liner搜索的lib的名称和路径)
    这个库的名字放在Object文件的默认库搜索记录的后面,linker搜索这个库就像你在命令行输入这个命令一样。你可以
    在一个源文件中设置多个库记录,它们在object文件中的顺序和在源文件中的顺序一样。如果默认库和附加库的次序是需要
    区别的,使用Z编译开关是防止默认库放到object模块。
    4、linker:指定一个连接选项,这样就不用在命令行输入或者在开发环境中设置了。

    只有下面的linker选项能被传给Linker.
    /DEFAULTLIB
    /EXPORT
    /INCLUDE
    /MANIFESTDEPENDENCY
    /MERGE
    /SECTION

    (1)/DEFAULTLIB:library

    /DEFAULTLIB 选项将一个 library 添加到 LINK 在解析引用时搜索的库列表。用 /DEFAULTLIB
      指定的库在命令行上指定的库之后和 .obj 文件中指定的默认库之前被搜索。
       忽略所有默认库 (/NODEFAULTLIB) 选项重写 /DEFAULTLIB:library。如果在两者中指定了相同的 library 名称,忽略库 (/NODEFAULTLIB:library) 选项将重写 /DEFAULTLIB:library。

    (2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]

    使用该选项,可以从程序导出函数,以便其他程序可以调用该函数。也可以导出数据。通常在 DLL 中定义导出。entryname 是调用程序要使用的函数或数据项的名称。ordinal 在导出表中指定范围在 1 至 65,535 的索引;如果没有指定 ordinal,则 LINK 将分配一个。NONAME 关键字只将函数导出为序号,没有 entryname。

    DATA 关键字指定导出项为数据项。客户程序中的数据项必须用 extern __declspec(dllimport) 来声明。
    有三种导出函数或者数据的方法,按照建议的使用顺序依次为:

    源代码中的 __declspec(dllexport)

    .def 文件中的 EXPORTS 语句

    LINK 命令中的 /EXPORT 规范

    所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。
    LINK 使用标识符的修饰形式。编译器在创建 .obj 文件时修饰标识符。如果 entryname 以其未修饰的形式指定给链接器(与其在源代码中一样),则 LINK 将试图匹配该名称。如果无法找到唯一的匹配名称,则 LINK 发出错误信息。当需要将标识符指定给链接器时,请使用 Dumpbin 工具获取该标识符的修饰名形式。

    (3)/INCLUDE:symbol
      /INCLUDE 选项通知链接器将指定的符号添加到符号表。

    若要指定多个符号,请在符号名称之间键入逗号 (,)、分号 (? 或空格。在命令行上,对每个符号指定一次 /INCLUDE:symbol。
    链接器通过将包含符号定义的对象添加到程序来解析 symbol。该功能对于添包含不会链接到程序的库对象非常有用。用该选项指定符号将通过 /OPT:REF 重写该符号的移除。

    #pragma 预处理指令详解
      在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
    #pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
      其格式一般为: #pragma para ; 其中para为参数,下面来看一些常用的参数。
    (1)message 参数
    它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
    #pragma message(“消息文本”)
    当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
    当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏,可以用下面的方法:
    #ifdef _X86
    #pragma message("_X86 macro activated!")
    #endif
    我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示"_86 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编译。
    你可以用#pragma 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关键字,可以帮我们连入一个库文件。如:

        #pragma  comment(lib, "comctl32.lib")
        #pragma  comment(lib, "vfw32.lib")
        #pragma  comment(lib, "wsock32.lib")
    

    每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。

    例如,对循环优化功能:
    #pragma loop_opt(on) // 激活
    #pragma loop_opt(off) // 终止

    有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,
    如“Parameter xxx is never used in function xxx”,可以这样:
    #pragma warn —100 // Turn off the warning message for warning #100
    int insert_record(REC r)
    { /
    function body */ }
    #pragma warn +100 // Turn the warning message for warning #100 back on
    函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。

    每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。

    #pragma pack 与 内存对齐问题
    许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。
    Win32平台下的微软C编译器(cl.exe for 80x86)在默认情况下采用如下的对齐规则: 任何基本数据类型T的对齐模数就是T的大小,即sizeof(T)。比如对于double类型(8字节),
    就要求该类型数据的地址总是8的倍数,而char类型数据(1字节)则可以从任何一个地址开始。
    Linux下的GCC奉行的是另外一套规则(在资料中查得,并未验证,如错误请指正): 任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模数是2,而其它所有超过2字节的数据类型(比如long,double)都以4为对齐模数。
    ANSI C规定一种结构类型的大小是它所有字段的大小以及字段之间或字段尾部的填充区大小之和。填充区就是为了使结构体字段满足内存对齐要求而额外分配给结构体的空间。那么结构体本身有什么对齐要求吗?有的,ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格。

    如何使用c/c++中的对齐选项
    vc6中的编译选项有 /Zp[1|2|4|8|16] ,/Zp1表示以1字节边界对齐,相应的,/Zpn表示以n字节边界对齐。n字节边界对齐的意思是说,一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上,取它们中的最小值。
    也就是:
    min ( sizeof ( member ), n)
    实际上,1字节边界对齐也就表示了结构成员之间没有空洞。/Zpn选项是应用于整个工程的,影响所有的参与编译的结构。
    要使用这个选项,可以在vc6中打开工程属性页,c/c++页,选择Code Generation分类,在Struct member alignment可以选择。
    要专门针对某些结构定义使用对齐选项,可以使用#pragma pack编译指令:

    (1) #pragma pack( [ n ] )
    该指令指定结构和联合成员的紧凑对齐。而一个完整的转换单元的结构和联合的紧凑对齐由/Zp 选项设置。
    紧凑对齐用pack编译指示在数据说明层设置。该编译指示在其出现后的第一个结构或联合说明处生效。
    该编译指示对定义无效。
    当你使用#pragma pack ( n ) 时, 这里n 为1、2、4、8 或16。
    第一个结构成员之后的每个结构成员都被存储在更小的成员类型或n 字节界限内。
    如果你使用无参量的#pragma pack, 结构成员被紧凑为以/Zp 指定的值。该缺省/Zp 紧凑值为/Zp8 。

    (2) 编译器也支持以下增强型语法:

        #pragma  pack( [ [ { push | pop } , ] [ identifier, ] ] [ n] )
    

    若不同的组件使用pack编译指示指定不同的紧凑对齐, 这个语法允许你把程序组件组合为一个单独的转换单元。
    带push参量的pack编译指示的每次出现将当前的紧凑对齐存储到一个内部编译器堆栈中。
    编译指示的参量表从左到右读取。如果你使用push, 则当前紧凑值被存储起来;
    如果你给出一个n 的值, 该值将成为新的紧凑值。若你指定一个标识符, 即你选定一个名称,
    则该标识符将和这个新的的紧凑值联系起来。

    带一个pop参量的pack编译指示的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。
    如果你使用pop参量且内部编译器堆栈是空的,则紧凑值为命令行给定的值, 并且将产生一个警告信息。
    若你使用pop且指定一个n的值, 该值将成为新的紧凑值。若你使用p o p 且指定一个标识符,
    所有存储在堆栈中的值将从栈中删除, 直到找到一个匹配的标识符, 这个与标识符相关的紧凑值也从栈中移出,
    并且这个仅在标识符入栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符,
    将使用命令行设置的紧凑值, 并且将产生一个一级警告。缺省紧凑对齐为8 。

    pack编译指示的新的增强功能让你编写头文件, 确保在遇到该头文件的前后的
    紧凑值是一样的。

    (3) 栈内存对齐

    在vc6中栈的对齐方式不受结构成员对齐选项的影响。它总是保持对齐,而且对齐在4字节边界上。

    #pragma comment(lib, “”)的路径问题
    common.cpp中有一条#pragma comment(lib,“common.lib”),其中common.cpp和common.lib处于同一个名为common的文件夹。
    而工程文件在其他文件夹,编译的时候,编译器从工程文件的同级目录查找common.lib,结果当然是找不到了。
    首先,由于这个common文件夹中的文件是所有人共享的,并不是每一个人的common绝对路径都相同,所以不能使用绝对路径链接lib。
    另外,由于多个项目使用这个common文件夹,但是它们的位置也各不相同,所以也不能使用相对于工程目录的相对路径。
    但是至少common.cpp和common.lib是处于同一个目录的,那么有办法让它自动找到吗?

    找到最佳解决方法了:
    common.lib还是common.lib不变,不用改名,然后
    #define LIBPATH(p,f) p##f
    #pragma comment(lib,LIBPATH(FILE, “…\srilm-lib\common.lib”))
    直接搞定,就算common.cpp.dir这个文件夹不存在也没有关系。

    改变程序入口函数
    复制代码
    #include

    #pragma comment(linker, "/ENTRY:foo ")

    int main()
    {
    return 0;
    }

    int foo()
    {
    std::cout << “hello world” << std::endl;
    return 0;
    }
    复制代码

    复制代码
    #include “stdio.h”
    void print()
    {
    *
    }
    void main()
    {
    }

    要求在*部分写代码使整个程序运行后输出“hello world”, 看雪的exile大哥做的

    #include "stdio.h"
    extern "C" int __cdecl mainCRTStartup(void);  //注意:若源文件是.c结尾的话,不需要这一句
    void print()
    { 
     #pragma comment(linker, "/entry:print")
      #pragma comment(linker, "/SECTION:.text,ERW")
     #pragma comment(lib, "msvcrt.lib")
     int mainCRTStartup();
     void main();
     
     __asm
     {
      MOV EAX, OFFSET main
      MOV BYTE PTR[EAX], 0xB8 //MOV EAX, 0x      //mov
      MOV DWORD PTR[EAX+1], OFFSET SHOWSTRING    //将printf语句地址放在eax+1处
      MOV WORD PTR[EAX+5], 0xE0FF // JMP EAX:FFE0
     }
     
     mainCRTStartup();
    
     __asm
     {
      leave
      ret
     }
    
     SHOWSTRING:
     printf("hello,world!\n");
     __asm
     {
       xor eax,eax
       ret
     }
    
    }
    void main()
    {
     }
    
    展开全文
  • #pragma pack (n) 与pragma pack(push,1)的区别 #pragma pack(n) //作用:C编译器按照n个字节对齐 #pragma pack() //作用:取消自定义对齐方式 #pragma pack(push, 1) //作用:是指把原来对齐方式设置压栈,...

    前言:今天看师傅的代码,我还以为是师傅写了个bug,兴致冲冲的改掉。结果细想之下发现我皮皮马就是个瓜皮,幸亏没跟师傅说他写了个bug,不然肯定得被笑死了。

    一、事情发生始末

    下面就先把涉及到的代码给大家看一下:

    typedef struct
    {
        Uint16 wSerialId;      
        Uint16 wProtocolFlag;
        Uint16 wMsgLen; 
        Uint8  byDevAddr; 
    }TMDBusTcpHead;`
    
    

    这里定义了一个Modbus协议的消息头的结构体,里面4个数据共7个字节,但是由于编译器字节对齐的原因,结构体占8个字节(原因在其他博客中细谈)。

    项目是收到Modbus协议数据_recvBuf进行解析,要将指针偏移到数据的协议头之后,也就是_recvBuf[7]这个位置。下面是我师傅写的地址偏移代码:

    char* NetIOMBusTcpImpl::getmsgBuf()
    {
        return &_recvBuf[sizeof(TMDBusTcpHead)];
    }
    

    看到这段代码之后,我瞬间心想:“握草,我读书少不要骗我。编译器字节对齐sizeof(TMDBusTcpHead)不是8吗?”然后我就改掉了。这绝对是我师傅写的时候忘记了,绝对是这个原因(心中窃喜,嘿嘿嘿)。

    冷静下来,有看了一遍代码,发现事情并没有这么简单,#pragma pack(push, 1)和#pragma pack(pop)这两行代码,我之前没注意(其实是没用过,不知道就自动忽略了)。然后去上网搜了一下它的用法,发现果然还是太年轻了,师傅就是师傅
    -_-.

    下面是#pragma pack(push,1)与#pragma pack(1)的用法与区别:

    二、#pragma pack(push,1)与#pragma pack(1)的用法与区别:

    1. 编译器默认字节对齐:

    首先粗略讲一下编译器字节对齐的问题,比如上面的结构体:

    typedef struct
    {
        Uint16 wSerialId;      
        Uint16 wProtocolFlag;
        Uint16 wMsgLen; 
        Uint8  byDevAddr; 
    }TMDBusTcpHead;`
    

    若不用#pragma pack(1)和#pragma pack()括起来,编译会按默认方式对齐(成员数据中的数据类型最大的对齐)。即按照Uint16(2字节对齐)
    字节(Uint16)对齐,即sizeof(TMDBusTcpHead) = 8;

    #pragma pack(push,1)与#pragma pack(1)的作用是给编译器用的参数设置,关于结构体内存的字节对齐,#pragma pack是指定数据在内存中的对齐方式。

    2. #pragma pack (n) 与pragma pack(push,1)的区别

    #pragma pack(n)				//作用:C编译器按照n个字节对齐
    #pragma pack()				//作用:取消自定义对齐方式
    
    #pragma pack(push, 1)		//作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐
    #pragma back(pop)			//作用:恢复对齐状态
    

    #pragma pack(push, 1)可能会比前者更优一点,但是二者其实也没有什么大的区别,比如:

    #prama pack(push)			//保持字节对齐状态
    #pragma pack(4)				//设定为4字节对齐
    相当于:#pragma  pack (push,4)  
    
    展开全文
  • 关注、星标公众号,不错过精彩内容素材来源:网络编辑整理:strongerHuang预处理指令#pragma 相信程序员都知道,但在所有的预处理指令中,#pragma 指令可能是最复杂的...
  • #line 指令可能由生成过程中的自动中间步骤使用。例如,如果行从原始的源代码文件中移除,但是您仍希望编译器基于文件中的原始行号生成输出,则可以移除行,然后用 #line 模拟原始行号
  • #pragma multi_compile #pragma shader_feature

    千次阅读 2019-06-29 10:45:38
    to achieve this in unity, u can add a #pragma multi_compile or #pragma shader_feature directive to a shader snippet. this also works in surface shaders. at run time, unity picks up the appropriate ...
  • 描述了#pragma 预处理指令的含义及用法。
  • 因为变体的编译时根据关键字的数量相乘得到的,比方说: #pragma multi_compile A B C #pragma multi_compile D E 那么就会生成 3 * 2 = 6种, 限制: 不能在api中使用本地关键字来改变全局关键字(比如着色器)。...
  • #pragma GCC diagnostic push与#pragma GCC diagnostic pop的使用 在GCC下,#pragma GCC diagnostic push用于记录当前的诊断状态,#pragma GCC diagnostic pop用于恢复诊断状态。 使用示例如下: #include <stdio...
  • #pragma用法详解

    千次阅读 2019-02-12 21:46:11
    #pragma预处理命令 #pragma可以说是C++中最复杂的预处理指令了,下面是最常用的几个#pragma指令: #pragma comment(lib,“XXX.lib”) 表示链接XXX.lib这个库,和在工程设置里写上XXX.lib的效果一样。 #pragma ...
  • #pragma mark-->#pragma

    2016-12-27 22:59:12
    Xcode 中#pragma mark 指令的使用:  功能:简单来说就是对代码的分组,方便代码查找和导航用的 它们告诉Xcode编译器,要在编辑器窗格顶部的方法和函数弹出菜单中将代码分隔开。一些类(尤其是一些控制器类)可能很长,...
  • 通过使用编译指示符#pragma multi_compile或者#pragma shader_feature,结合判定宏是否启用的指令defined,还有引擎C#语言层的Material类成员函数EnableKeyworld或者Shader类静态成员函数EnableKeyword, ...
  • c++中#pragma用法详解

    千次阅读 2019-04-17 09:58:40
    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或...
  •  #pragma pack(n) ...每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐...程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。  
  • C #pragma pack(push,1) #pragma pack(pop)解析

    千次阅读 2018-08-14 17:39:48
    #pragma pack( push, 1 ) #else #pragma pack(1) #endif Typedef struct { } #ifdef _WIN32 #pargma pack(pop) #else #pragma pack() #endif   二、对 #pragma pack()的理解 在程序中,我们有时候在定义...
  • 今天在看源码的时候,遇到以下内容: #pragmawarning(push)是保存当前的编译器警告状态; #pragmawarning(pop)是恢复原先的警告状态。...#pragma warning(disable : 4100) // unused parameter #endif // _MSC_VE...
  • #pragma comment()的使用

    2012-08-12 17:19:20
    #pragma comment()的使用
  • C++ #pragma 用法详解

    千次阅读 2019-07-19 14:00:06
    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或...
  • #pragma pack 用法详解

    千次阅读 2018-08-21 14:26:54
    #pragma pack 用法详解 pack为struct、union和class等的成员对齐指定字节边界,与编译选项(属性 -&gt; 配置属性 -&gt; C/C++ -&gt;代码生成 -&gt; 结构成员对齐)的/Zp开关不同,它不针对整个项目,...
  • #pragma的常用方法讲解

    万次阅读 多人点赞 2018-11-25 22:04:26
    我们在写代码时,总会遇到头文件多次包含的情况,刚开始时我们使用宏定义进行控制,之后发现有#pragma once这样简单的东西,当时是很兴奋,以为#pragma就这一种用法。唉~,现在想想当时还是年轻啊,不过还是年轻好啊...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 411,739
精华内容 164,695
关键字:

#pragma