精华内容
参与话题
问答
  • 一个完整的URL 解析过程

    万次阅读 2018-12-29 10:35:17
    网页解析的全过程 1、用户输入网址,浏览器发起DNS查询请求 用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址 域名解析服务器是基于UDP实协议实现的一个应用程序,通常通过监听53...

    网页解析的全过程

    1、用户输入网址,浏览器发起DNS查询请求

    用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址

    域名解析服务器是基于UDP实协议实现的一个应用程序,通常通过监听53端口来获取客户端的域名解析请求。DNS查找过过程如下:

    浏览器缓存-浏览器会缓存DNS记录一段时间。有趣的是操作系统没有告诉浏览器存储DNS记录的时间,这样不同浏览器会记录他们各自固定的一个时间(2分钟到30分钟不等)

    系统缓存-如果在浏览器缓存中没有找到需要的记录,浏览器会做一个系统调用(gethostbyname)。这样便可获得系统缓存中的记录。

    路由器缓存-接着前面的查询请求发向路由器,他一般会有自己的DNS缓存

    ISP DNs缓存-接下来要check的就是ISP缓存DNS的服务器。在这一般都能找到相应的缓存记录。

    递归搜索-你的ISP的DNS服务器从域名服务器开始进行递归搜索,从com顶级域名服务器到Facebook的域名服务器。一般DNS服务器的缓存中会有.com域名服务器中的域名,所以到顶级服务器的匹配过程不是那么必要了。

    2、建立TCP连接

    浏览器通过DNS获取到web服务器真的IP地址后,便向服务器发起TCP连接请求,通过tcp的三次握手建立好连接后,浏览器便可以将http请求数据通过发送给服务器了。

    3、浏览器向web服务器发送一个http请求

    http请求时基于tcp协议之上的应用层协议--超文本传输协议。一个http事务由一条(从客户端发往服务器的)请求命令和一个(从服务器发回客户端的)响应结果组成。

    GET http://www.cricode.com/ HTTP/1.1

    Host: www.cricode.com

    Connection: keep-alive

    Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

    User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36

    Accept-Encoding: gzip,deflate,sdch

    Accept-Language: zh-CN,zh;q=0.8

    4、发送响应数据给客户端

    web服务器通过监听80端口,来获取客户端的http请求。与客户端建立好TCP连接后,web服务器开始接受客户端发来的数据,并通过http解码,从接收到的网络数据中解析出请求的url信息以前其他诸如Accept-Encoding、Accept-Language等信息。Web服务器根据http请求头的信息,得到响应数据返回给客户端。一个典型的http响应头数据报如下:

    HTTP/1.1 200 OK

    Date: Fri, 24 Oct 2014 13:55:18 GMT

    Server: Apache

    X-Powered-By: PHP/5.4.32

    Keep-Alive: timeout=5, max=10000

    Connection: Keep-Alive

    Transfer-Encoding: chunked

    Content-Type: text/html; charset=UTF-8

    a0f6

    <</span>!DOCTYPE HTML>

    <</span>html>

    <</span>head>

    <</span>meta charset="UTF-8">

    <</span>meta http-equiv="X-UA-Compatible" content="IE=10,IE=9,IE=8">

    <</span>meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">

    <</span>title><</span>/title>

    <</span>body class="home"><</span>/body>

    <</span>/html>

    至此,一个http通信过程完成。web服务器会根据http请求头中的Connection字段值决定是否关闭TCP链接通道,当Connection字段值为keep-alive时,web服务器不会立即关闭此链接。

    5、浏览器解析http response

    (1)html文档解析(DOM Tree)

    在浏览器没有完整的接收全部HTML文档时,它就已经开始显示这个页面了。生成解析树解析即dom树,是由dom元素及属性节点组成,树的根是docunment对象。

    (2)浏览器发送获取嵌入在html中的对象

    加载过程中遇到外部css文件,浏览器另外发出一个请求,来获取css文件。遇到图片资源,浏览器也会另发出一个请求,来获取图片资源。这是异步请求,并不会影响html文档进行加载。

    但是当文档加载过程中遇到js文件,html文档会挂起渲染的线程,不仅要等待文档中的js文件加载完毕,还要等待解析执行完毕,才能恢复html文档的渲染线程。

    (3)css解析

    浏览器下载css文件,将css文件解析为样式表对象,并来用渲染dom tree。该对象包含css规则,该规则包含选择器和声明对象。

    css元素遍历的顺序,是从树的低端向上遍历。

    (4)js解析

    浏览器UI线程:单线程,大多数浏览器让一个单线程共用于执行JavaScript和更新用户界面

    js阻塞页面:浏览器里的http请求被阻塞一般都是由js所引起,具体原因是js文件在下载完毕之后会立即执行,而js执行时候会阻塞浏览器的其他行为,有一段时间是没好网络请求被处理的,这段空闲时间就是所谓的http请求被阻塞。

     

    js被阻塞的原因:之所以会阻塞U线程的执行,是因为js能控制UI的展示,而页面加载的规则是要顺序执行,所以在碰到js代码时候UI线程会首先执行他。

     

     

    展开全文
  • [转帖]解析#pragma指令

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

    在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
    #pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。
    依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
        其格式一般为: #pragma  para
        其中para为参数,下面来看一些常用的参数。
    (1)message 参数

        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/"] ] )
        它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

    在主文件中,用#pragma data_seg建立一

    个新的数据段并定义共享数据,其具体格式为:

    #pragma data_seg ("shareddata") //名称可以

    //自己定义,但必须与下面的一致。

    HWND sharedwnd=NULL;//共享数据

    #pragma data_seg()

     

    仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的 (其效果是相同的),一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED 另一种方法是在项目设置链接选项(Project Setting --〉Link)中加入如下语句: /SECTION:shareddata,rws

    第一点:什么是共享数据段?为什么要用共享数据段??它有什么用途??
    在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。

    因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。

     

    #pragma data_seg预处理指令用于设置共享数据段。例如:

    #pragma data_seg("SharedDataName") HHOOK hHook=NULL; //必须在定义的同时进行初始化!!!!#pragma data_seg()

    在#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。再加上一条指令#pragma comment(linker,"/section:.SharedDataName,rws"),[注意:数据节的名称is case sensitive]那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。

     

    当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里(以下简称"地址空间")。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。(这项技术又叫code Injection技术,被广泛地应用在了病毒、黑客领域!呵呵^_^)

     

    第二点:在具体使用共享数据段时需要注意的一些问题!

    Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of all the DLLs global and static variables. (注意: 即使是全局变量和静态变量也都不是共享的!) If your DLL needs to share data with other instances of it loaded by other applications, you can use either of the following approaches:

    · Create named data sections using the data_seg pragma.

    · Use memory mapped files. See the Win32 documentation about memory mapped files.

    Here is an example of using the data_seg pragma:

    #pragma data_seg (".myseg")
    int i = 0;
    char a[32] = "hello world";
    #pragma data_seg()

    data_seg can be used to create a new named section (.myseg in this example). The most typical usage is to call the data segment .shared for clarity. You then must specify the correct sharing attributes for this new named data section in your .def file or with the linker option /SECTION:.MYSEC,RWS. (这个编译参数既可以使用pragma指令来指定,也可以在VC的IDE中指定!)

    There are restrictions to consider before using a shared data segment:

    · Any variables in a shared data segment must be statically initialized. In the above example, i is initialized to 0 and a is 32 characters initialized to hello world.

    · All shared variables are placed in the compiled DLL in the specified data segment. Very large arrays can result in very large DLLs. This is true of all initialized global variables.

    · Never store process-specific information in a shared data segment. Most Win32 data structures or values (such as HANDLEs) are really valid only within the context of a single process.

    · Each process gets its own address space. It is very important that pointers are never stored in a variable contained in a shared data segment. A pointer might be perfectly valid in one application but not in another.

    · It is possible that the DLL itself could get loaded at a different address in the virtual address spaces of each process. It is not safe to have pointers to functions in the DLL or to other shared variables.

    应用一:单应用程序。

    有的时候我们可能想让一个应用程序只启动一次,就像单件模式(singleton)一样,实现的方法可能有多种,这里说说用#pragma data_seg来实现的方法,很是简洁便利。

    应用程序的入口文件前面加上

    #pragma data_seg("flag_data")
    int app_count = 0;
    #pragma data_seg()
    #pragma comment(linker,"/SECTION:flag_data,RWS")

    然后程序启动的地方加上

     if(app_count>0)    // 如果计数大于0,则退出应用程序。
     {
      //MessageBox(NULL, "已经启动一个应用程序", "Warning", MB_OK);

      //printf("no%d application", app_count);

      return FALSE;
     }
     app_count++;

    (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中包括窗体
    外观的定义。   [Page]


    (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(...)
    该指令的格式为
    #pragma comment( "comment-type" [, commentstring] )
     

    该指令将一个注释记录放入一个对象文件或可执行文件中,
    comment-type(注释类型):可以指定为五种预定义的标识符的其中一种
    五种预定义的标识符为:

    compiler:将编译器的版本号和名称放入目标文件中,本条注释记录将被编译器忽略
             如果你为该记录类型提供了commentstring参数,编译器将会产生一个警告
    例如:#pragma comment( compiler )

    exestr:将commentstring参数放入目标文件中,在链接的时候这个字符串将被放入到可执行文件中,
           当操作系统加载可执行文件的时候,该参数字符串不会被加载到内存中.但是,该字符串可以被
           dumpbin之类的程序查找出并打印出来,你可以用这个标识符将版本号码之类的信息嵌入到可
           执行文件中!

    lib:这是一个非常常用的关键字,用来将一个库文件链接到目标文件中


    常用的lib关键字,可以帮我们连入一个库文件。 
    例如:
    #pragma comment(lib, "user32.lib") 
    该指令用来将user32.lib库文件加入到本工程中


    linker:将一个链接选项放入目标文件中,你可以使用这个指令来代替由命令行传入的或者在开发环境中
           设置的链接选项,你可以指定/include选项来强制包含某个对象,例如:
           #pragma comment(linker, "/include:__mySymbol")

    你可以在程序中设置下列链接选项

    /DEFAULTLIB
    /EXPORT
    /INCLUDE
    /MERGE
    /SECTION
    这些选项在这里就不一一说明了,详细信息请看msdn!

    user:将一般的注释信息放入目标文件中commentstring参数包含注释的文本信息,这个注释记录将被链接器忽略
    例如:
    #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )

     

    每个编译程序可以用#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 [Page]
    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。[Page]
        第一个结构成员之后的每个结构成员都被存储在更小的成员类型或n 字节界限内。
    如果你使用无参量的#pragma  pack, 结构成员被紧凑为以/Zp 指定的值。该缺省/Zp 紧凑值为/Zp8 。


    (2) 编译器也支持以下增强型语法:
        #pragma  pack( [ [ { push | pop } , ] [ identifier, ] ] [ n] )

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

        带一个pop参量的pack编译指示的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。
    [NextPage]

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

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


    (3) 栈内存对齐

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


     

     

    补充:关于#pragma warning
    1.       #pragma warning只对当前文件有效(对于.h,对包含它的cpp也是有效的),而不是对整个工程的所有文件有效。当该文件编译结束,设置也就失去作用。

    2.       #pragma warning(push)

    存储当前报警设置。

    #pragma warning(push, n)

    存储当前报警设置,并设置报警级别为n。n

    为从1到4的自然数。

    3.       #pragma warning(pop)

    恢复之前压入堆栈的报警设置。在一对push和pop之间作的任何报警相关设置都将失效。

    4.       #pragma warning(disable: n)

    将某个警报置为失效

    5.       #pragma warning(default: n)

    将报警置为默认

    6.       某些警告如C4309是从上到下生效的。即文件内#pragma warning从上到下遍历,依次生效。

    例如:

    void func()

    {

          #pragma warning(disable: 4189)

          char s;

          s = 128;

          #pragma warning(default: 4189)

          char c;

          c = 128;

    }

    则s = 128

    不会产生C4309报警,而C4309会产生报警。

    7.       某些警告例如C4189是以函数中最后出现的#pragma warning设置为准的,其余针对该报警的设置都是无效的。

    例如:

    void func()

    {

          #pragma warning(disable: 4189)

          int x = 1;

          #pragma warning(default: 4189)

    }

    则C4189仍然会出现,因为default指令是函数的最后一条。在该文件内的其他函数中,如果没有重新设置,C4189也是以#pragma warning(default: 4189)为准。如果重新设置,同样是按照其函数中的最后一个#pragma warning为准。

    8.       某些警告(MSDN认为是大于等于C4700的警告)是在函数结束后才能生效。

    例如:

    #pragma warning(disable:4700)

    void Func()

    {

    int x;

    int y = x;  

              #pragma warning(default:4700)



               int z= x;

    }

    则y = x和z = x都不会产生C4700报警。只有在函数结束后的后的另外一个函数中,#pragma warning(default:4700)才能生效。
     

     
    展开全文
  • 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或...
    在所有的预处理指令中,#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编译。你可以用#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指令用法汇总和解析

    千次阅读 2014-02-01 11:36:45
    #pragma指令用法汇总和解析 一. message 参数。 message 它能够在编译信息输出窗  口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:  #pragma message(“消息文本”)  当编译器遇到这...

    #pragma指令用法汇总和解析

    一. message 参数。

    message
    它能够在编译信息输出窗 
    口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: 

    #pragma message(“消息文本”) 

    当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。 
    当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条
    指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法 
    #ifdef _X86 
    #pragma message(“_X86 macro activated!”) 
    #endif 
    当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_ 
    X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了 

    二. 另一个使用得比较多的#pragma参数是code_seg。格式如: 

    #pragma code_seg( [ [ { push | pop}, ] [ identifier, ] ] [ "segment-name" [, "segment-class" ] )
    该指令用来指定函数在.obj文件中存放的节,观察OBJ文件可以使用VC自带的dumpbin命令行程序,函数在.obj文件中默认的存放节
    为.text节
    如果code_seg没有带参数的话,则函数存放在.text节中
    push (可选参数) 将一个记录放到内部编译器的堆栈中,可选参数可以为一个标识符或者节名
    pop(可选参数) 将一个记录从堆栈顶端弹出,该记录可以为一个标识符或者节名
    identifier (可选参数) 当使用push指令时,为压入堆栈的记录指派的一个标识符,当该标识符被删除的时候和其相关的堆栈中的记录将被弹出堆栈
    "segment-name" (可选参数) 表示函数存放的节名
    例如:
    //默认情况下,函数被存放在.text节中
    void func1() {                  // stored in .text
    }

    //将函数存放在.my_data1节中
    #pragma code_seg(".my_data1")
    void func2() {                  // stored in my_data1
    }

    //r1为标识符,将函数放入.my_data2节中
    #pragma code_seg(push, r1, ".my_data2")
    void func3() {                  // stored in my_data2
    }

    int main() {
    }

    三. #pragma once (比较常用) 

    这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次
    四. #pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。

    BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。  
    有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,
    如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。  
    五. #pragma warning指令

    该指令允许有选择性的修改编译器的警告消息的行为

    指令格式如下:
    #pragma warning( warning-specifier : warning-number-list [; warning-specifier : warning-number-list...]
    #pragma warning( push[ ,n ] )
    #pragma warning( pop )

    主要用到的警告表示有如下几个:

    once:只显示一次(警告/错误等)消息
    default:重置编译器的警告行为到默认状态
    1,2,3,4:四个警告级别
    disable:禁止指定的警告信息
    error:将指定的警告信息作为错误报告

    如果大家对上面的解释不是很理解,可以参考一下下面的例子及说明
    #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)

    在使用标准C++进行编程的时候经常会得到很多的警告信息,而这些警告信息都是不必要的提示,
    所以我们可以使用#pragma warning(disable:4786)来禁止该类型的警告

    在vc中使用ADO的时候也会得到不必要的警告信息,这个时候我们可以通过
    #pragma warning(disable:4146)来消除该类型的警告信息

    六. pragma comment(...)
    该指令的格式为
    #pragma comment( "comment-type" [, commentstring] )

    该指令将一个注释记录放入一个对象文件或可执行文件中,
    comment-type(注释类型):可以指定为五种预定义的标识符的其中一种
    五种预定义的标识符为:

    compiler:将编译器的版本号和名称放入目标文件中,本条注释记录将被编译器忽略
             如果你为该记录类型提供了commentstring参数,编译器将会产生一个警告
    例如:#pragma comment( compiler )

    exestr:将commentstring参数放入目标文件中,在链接的时候这个字符串将被放入到可执行文件中,
           当操作系统加载可执行文件的时候,该参数字符串不会被加载到内存中.但是,该字符串可以被
           dumpbin之类的程序查找出并打印出来,你可以用这个标识符将版本号码之类的信息嵌入到可
           执行文件中!

    lib:这是一个非常常用的关键字,用来将一个库文件链接到目标文件中

    常用的lib关键字,可以帮我们连入一个库文件。 
    例如:
    #pragma comment(lib, "user32.lib") 
    该指令用来将user32.lib库文件加入到本工程中

    linker:将一个链接选项放入目标文件中,你可以使用这个指令来代替由命令行传入的或者在开发环境中
           设置的链接选项,你可以指定/include选项来强制包含某个对象,例如:
           #pragma comment(linker, "/include:__mySymbol")

    你可以在程序中设置下列链接选项

    /DEFAULTLIB
    /EXPORT
    /INCLUDE
    /MERGE
    /SECTION
    这些选项在这里就不一一说明了,详细信息请看msdn!

    user:将一般的注释信息放入目标文件中commentstring参数包含注释的文本信息,这个注释记录将被链接器忽略
    例如:
    #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )

    #pragma data_seg——新的尝试- -

                                          

    #pragma data_seg之前从来没有用过,今天经同事指点,找出了它的一个妙用。

    持续整理中......

    #pragma data_seg介绍

    应用一:单应用程序。

        有的时候我们可能想让一个应用程序只启动一次,就像单件模式(singleton)一样,实现的方法可能有多种,这里说说用#pragma data_seg来实现的方法,很是简洁便利。

    应用程序的入口文件前面加上

    #pragma data_seg("flag_data")
    int app_count = 0;
    #pragma data_seg()
    #pragma comment(linker,"/SECTION:flag_data,RWS")

    然后程序启动的地方加上

    if(app_count>0)    // 如果计数大于0,则退出应用程序。
    {
       //MessageBox(NULL, "已经启动一个应用程序", "Warning", MB_OK);

       //printf("no%d application", app_count);
     return FALSE;
    }
    app_count++;

    通过#pragma pack(n)改变C编译器的字节对齐方式
    在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
    例如,下面的结构各成员空间分配情况:
    struct test
    {
            char x1; // 偏移地址为0
            short x2;// 偏移地址为[2,3]
            float x3;// 偏移地址为[4,7]
            char x4; // 偏移地址为8
    };
          结构的第一个成员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字节对齐方式

    #pragma pack规定的对齐长度,实际使用的规则是: 
    结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 
    也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。 
    而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack指定值 之间,较小的那个进行。

    在IAR编译器里用关键字来__interrupt来定义一个中断函数。用#pragma vector来提供中断函数的入口地址。

    #pragma vector = 0x12    //定时器0溢出中断入口地址
    __interrupt void time0(void)
    {
     ;
    }
        上面的入口地址写成#pragma vector=TIMER0_OVF_vect更直观,每种中断的入口地址在头文件里有描述。函数名称time0可以为任意名称。中断函数会自动保护局部变量,但不会保护全局变量。

    1 .内在函数也可以称为本征函数
            编译器自己编写的能够直接访问处理器底层特征的函数。在intrinsics.h中有描述完整类型在comp_a90.h里有进一步的简化书写方式

    延时函数,以周期为标准
            __delay_cycles(unsigned long );
            如果处理器频率为1M,延时100us,如下:
            __delay_cycles(100 );
            当然你也可以对该函数进行修改:
            #define CPU_F 1000000
            #define delay_us (unsigned long) __delay_cycles((unsigned long )*CPU_F)
            #define delay_ms (unsigned long) __delay_cycles((unsigned long )*CPU_F/1000)

    2.中断指令
       __disable_interrupt( );//插入CLI指令, 也可以用_CLI();也可以SREG_Bit7=0;
        __enable_interrupt( );// 插入SEI指令,也可以用_SEI();也可以SREG_Bit7=1;
        其实对于状态字的置位和清零只有BSET S 和BCLR S两条指令。像SEI不过是BSET 7;的另一个名字而已。AVR指令中还有很多类似的现象,如:ORI 和 SBR 指令完全一样,号称130多条指令的AVR其实没有那么多指令的。

    3.从FLASH空间指定地址读取数据
    __extended_load_program_memory(unsigned char __farflash *);
    __load_program_memory(unsigned char __flash *);


    4.乘法函数
    __fracdtional_multiply_signed(signed char, signed char);
    __fractional_multiply_signed_with_unsigned(signed char, unsigned char);
    __fractional_multiply_unsigned(unsigned char, unsigned char);
    //以上为定点小数乘法
    __multiply_signed(signed char, signed char);//有符号数乘法
    __multiply_signed_with_unsigned(signed char, unsigned char);
    //有符号数和无符号数乘法
    __multiply_unsigned(unsigned char, unsigned char);//无符号数乘法

     5.半字节交换指令
    __swap_nibbles(unsigned char);

    6.MCU控制指令
    __no_operation();//空操作指令
    _NOP();
    __sleep();//休眠指令
    _SLEEP();
    __watchdog_reset();//看门狗清零
    _WDR();

     

    注意:在实现过程中可能涉及到.XCL连接文件的更改,请保存好原来的.XCL文件!
    1.打开相应的*c.xcl文件,用"-Z(CONST)段名=程序定位的目标段-FFDF"定义段的起始地址.
    2.在自己的C程序中用#pragma constseg(段名)定位自己的程序
    3.结束后恢复编译器的默认定位#pragma default
    IAR 1.26b环境下:
    1、将常量数组放在FLASH段自定议的MYSEG段中
    原来的MSP430F149 XCL文件如下:
    // Constant data
    -Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=1100-FFDF
    如果想从中分出一部分做数据存储区,做如下修改:
    -Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=1500-FFDF //将1100-14FF从ROM中分出存储arry数

    -Z(CONST)MYSEG=1100-14FF区间大小可自行决定
    在程序中描写如下即可:
    #pragma memory = constseg(MYSEG) //在.XCL文件中修改
    char arry[]={1,2,3,4,5,6,7};
    #pragma memory = default
    2、将变量放入所命名的段
    在XCL文件中开辟一段MYSEG段,如上所述
    #pragma memory = dataseg(MYSEG)
    char i;
    char j;
    int k;
    #pragma memory = default

    IAR3.10A环境下
    xcL文件的更改方法如上
    数据定位方法如下三种
    1、__no_init char alpha @ 0x0200; 
    2、#pragma location=0x0202
    const int beta; 
    3、const int gamma @ 0x0204 = 3; 
    或;
    1、__no_init int alpha @ "MYSEGMENT"; //MYSEGMENT段可在XCL中开辟
    2、#pragma location="MYSEGMENT"
    const int beta; 
    3、const int gamma @ "MYSEGMENT" = 3; 
    函数定位如下面两种写法
    1、
    void g(void) @ "MYSEGMENT" //MYSEGMENT段可在XCL中开辟
    {
    }
    2、
    #pragma location="MYSEGMENT"
    void h(void)
    {
    }

     

    展开全文
  • 抓包protobuf反解析

    千次阅读 2019-09-06 13:56:51
    网上也有不少问关于这方面的,或许有人已经研究出来了,但是不肯放干货啊。只能自己探索了。 首先我用的抓包工具是Charles,抓包是能看到内容的。Charles本身是用java写的,所以很容易看到源代码。...
  • 解析解与数值解的区别

    万次阅读 2017-08-01 09:42:58
    这段时间一直在听数学学院的课,反反复复听到“解析解”和“数值解”,始终不明白这两者的区别。  经学长解释,总算有点眉目:  解析解就是给出解的具体函数形式,从解的表达式中就可以算出任何对应值;数值...
  • java--解析xml文件详解

    2020-08-20 15:43:54
    // 创建一个XML解析器对象 SAXReader reader = new SAXReader(); // 读取XML文档,返回Document对象 Document document = reader.read(file); // 获取根元素节点 Element root = document.getRootElement(); // 获取...
  • 域名解析指向详细操作(图解)

    千次阅读 2019-08-22 15:27:00
    域名注册好之后,只说明你对这个域名拥有了使用权,如果不进行域名解析,那么这个域名就不能发挥真正的作用。 域名如何解析指向到虚拟主机?指向空间有两步骤: (首先 登陆美橙管理中心→英文域名管理→管理→域名...
  • wifi 问题解答

    千次阅读 2012-06-06 21:55:50
    9-01.无线局域网都由哪几部分组成?无线局域网中的固定基础设施对网络的性能有何影响?接入点AP是否就是无线局域网中的固定基础设施? 答:无线局域网由无线网卡、无线接入点(AP)、计算机和有关设备组成,采用单元...
  • 尤承业编著的《解析几何》是学习几何学的入门教材。书中既讲解了空间解析几何的基本内容和方法(向量代数,仿射坐标系,空间的直线和平面,常见曲面等),等讲解了仿射几何学中的基本内容和思想(仿射坐标变换,二次...
  • 本书是在《解析几何》(第三版)的基础上,由原作者稍作修订而成,全书分六章,即向量与坐标,轨迹与方程,平面与空间直线,柱面、锥面、旋转曲面与二次曲面,二次曲线的一般理论与二次曲面的一般理论以及附录:矩阵...
  • 解析几何(吕林根).pdf

    热门讨论 2008-12-02 16:41:14
    解析几何(吕林根).pdf 第三版 高等教育出版社
  • 解析几何(吕林根)Doc版,是中科大精品课程使用的教案!
  • 高等数学空间解析几何试题及题解,Word文档
  • 这是解析几何简明教程 文档本身十分清晰 适合初学解析几何的同学参考
  • 同时有那本解几书的内容和别人做的笔记 word文档 从同学那淘来的~
  • 解析几何,尤承业,kindle书籍,azw3格式,可以直接在kindle上阅读,或者使用calibre转化为epub、mobi、doc/docx等格式。排版较好。
  • 解析几何解析几何解析几何解析几何解析几何解析几何解析几何解析几何解析几何解析几何
  • 解析几何(吕林根).pdf.rar
  • 高等代数与解析几何!

    2009-02-24 10:51:58
    高等代数与解析几何,高等代数与解析几何,高等代数与解析几何,高等代数与解析几何.
  • 空间解析几何相关例题的精选,配合相关教材可以达到预期的学习效果。
  • PPT格式。本课件主要介绍行列式、矩阵、向量空间、线性方程组、线性变换、欧式空间、二次型、解析几何等内容。本课件大小为16MB,包含文字10万,图形图像4987幅(大量公式),教学设计100个等等。
  • 本答案书包含了线性代数与空间解析几何的所有课后习题答案,解题步骤清晰
  • 空间解析几何

    千次阅读 2015-02-12 17:35:11
    解析几何是用代数方法研究几何对象之间的关系和性质的一门几何学分支。通俗讲就是通过建立坐标系来用方程描述几何图形。 在解析几何创立以前,几何与代数是彼此独立的两个分支。而它的出现使形与数统一起来,这是...
  • 线性代数与空间解析几何第四版,郑宝东主编,郑宝东,王忠英编,2013年版本
  • 向量与空间解析几何思维导图
  • 本书包含了原高等代数与解析几何两门基础课的主要内容的答案。 (习题答案)
  • §1 基本计算公式 序号 图形 计算公式 1 平面上两点间的距离: 2 空间中两点间的距离: 3 平面上分线段为定比的分点坐标(定比分点公式): ...注: M为A1A2
  • 线性代数与解析几何
  • 高等代数与解析几何。高等教育出版社。作者:孟道骥

空空如也

1 2 3 4 5 ... 20
收藏数 2,700,695
精华内容 1,080,278
关键字:

解析