• C语言查漏补缺


    1.C99中struct的柔性数组

    // C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,
    // 但结构中的柔性数组成员前面必须至少一个其他成员。
    // 柔性数组成员允许结构中包含一个大小可变的数组。
    // sizeof 返回的这种结构大小不包括柔性数组的内存。
    typedef struct st_type
    {
    int i;
    int a[]; // int a[0];
    }type_a; 
    // type_a 为 typede f定义的 结构体 st_type 的别名,方便使用
    // 定义一个可变长的结构体,用 sizeof(type_a)得到的只有 4,就是 sizeof(i)=sizeof(int)。
    // 给结构体分配内存
    type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
    // 为结构体指针 p 分配了一块内存。用 p->a[n]就能简单地访问可变长元素。
    // 我们再用 sizeof(*p)测试结构体的大小,发现仍然为 4。
    // 在定义这个结构体的时候,模子的大小就已经确定不包含柔性数组的内存大小。
    // 柔性数组只是编外人员,不占结构体的编制。
    // 用 free 函数来释放内存:
    // free(p);
    

    2. 利用共用体测试机器大小端

    int checkDuan( )
    {
         union
         {
              int i;   // 4字节
              char ch; // 存放在 低地址
         }c;
         c.i = 127; //大端模式:高地址:0x007F 低地址:0x0000
                    // 小端模式: 高地址:0x0000 低地址:0x007F
    
         printf("%x",c.ch);
    return c.ch==127; 
    }
    

    3. typedef常见用法

    1.	常规变量类型定义:typedef unsigned char uchar
    描述:uchar等价于unsigned char类型定义
                           
    2.	数组类型定义:typedef int array[2];(注:可理解为typedef int[] array)
         描述:array 等价于 int [2]定义; array a 声明等价于int a[2]声明
         typedef int array[M][N]; 
    	描述: array等价于 int[M][N]定义; array a声明等价于int a[M][N]声明
    3.	指针类型定义: typedef int * pointer;   
    	描述: pointer等价于 int*定义; pointer p 声明等价于int* a声明
         typedef int *pointer[M]; 
    	描述: pointer等价于 int*[M]定义; pointer p声明等价于int*a[M]声明
    4.函数地址说明描述:int func(void);       
                        unsigned long funcAddr=(unsigned long)func;
                        funcAddr 的值是 func 函数的首地址
    5.函数声明例如:typedef int func(void); 
                     func 等价于 int(void)类型函数
    6.函数指针例如: typedef int (*func)(void) 
                     func等价于int (*)(void)类型  
                     func pf 等价于 int(*pf)(void)声明,pf是一个函数指针变量
    

    4. 预处理

    
    预处理名称    意 义  
    
    #define      宏定义
    #undef       撤销已定义过的宏名  
    #include    使编译程序将另一源文件嵌入到带有#include 的源文件中  
    #if         条件编译,#if 的一般含义是如果#if 后面的常量表达式为 true,    
                则编译它与#endif 之间的代码,否则跳过这些代码。  
    #endif      命令 #endif 标识一个 #if 块的结束。   
    #else       #else 命令的功能有点象 C 语言中的 else ,    
                #else 建立另一选择(在# if 失败的情况下)。   
    #elif       #elif 命令意义与 else if 相同,   
                它形成一个 if else-if 阶梯状语句,可进行多种编译选择。   
    
    #ifdef/#ifndef    用#ifdef 与 #ifndef 命令分别表示“如果有定义”及“如果无定义”,   
                 是条件编译的另一种方法。    
    #line         改变当前行数和文件名称,它们是在编译程序中预先定义的标识符,   
                  命令的基本形式如下:   
                  #line number["filename"]      
    #error        编译程序时,只要遇到 #error 就会生成一个编译错误提示消息,并停止编译     
    #pragma       为实现时定义的命令,它允许向编译程序传送各种指令
    		例如,编译程序可能有一种选择,它支持对程序执行的跟踪。   
                  可用#pragma语句指定一个跟踪选择。 
    
    另外 ANSI 标准 C 还定义了如下几个宏:   
                  _LINE_ 表示正在编译的文件的行号       
                  _FILE_ 表示正在编译的文件的名字      
                  _DATE_ 表示编译时刻的日期字符串,例如: "25 Dec 2007"    
                  _TIME_ 表示编译时刻的时间字符串,例如: "12:30:55"    
                  _STDC_ 判断该文件是不是定义成标准 C 程序  
    

    5. #pragma编译

    1. #pragma message("消息文本") 
         它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
         当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
         假设我们希望判断自己有没有在源代码的什么地方定义了_X86 这个宏可以用下面的方法:
         #ifdef _X86
         #pragma message(“_X86 macro activated!”)
         #endif
    
    2. #pragma code_seg()
         另一个使用得比较多的 pragma 参数是 code_seg。
         格式如:
         #pragma code_seg( ["section-name"[,"section-class"] ] )
         它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。
    
    3. #pragma once 编译一次
         比较常用,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次, 
         但是考虑到兼容性并没有太多的使用它。
    
    4. #pragma hdrstop
         #pragma hdrstop 表示预编译头文件到此为止,后面的头文件不进行预编译。 
         你可以用#pragma startup 指定编译优先级,
    	如果使用了#pragma package(smart_init) ,
         BCB就会根据优先级的大小先后编译.
    
    5. #pragma resource 载入资源
         #pragma resource "*.dfm"  表示把*.dfm 文件中的资源加入工程。 
         *.dfm 中包括窗体外观的定义。
    
    6. #pragma warning 错误信息
         #pragma warning(disable:4507 34) // 不显示 4507 和 34 号警告信息
         #pragma warning(once:4385)       // 4385 号警告信息仅报告一次
         #pragma warning(error:164)       // 把 164 号警告信息作为一个错误。
    
         #pragma warning( push )保存所有警告信息的现有的警告状态。
         #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为 n。
         #pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的一切改动取消。
    
    7. #pragma pack(用于指定内存对齐的方式(按指定的字节数进行对齐)) 和 内存对齐问题(降低访存消耗)
    struct TestStruct1
    {
         char c1;  // 1字节   数据结构(尤其是栈)应该尽可能地在自然边界上对齐。(大小为4的倍数)
         short s;  // 2字节
         char c2;  // 1字节
         int i;    // 4字节
    }
    
    |c1| - |     s |   编译器在默认情况下按照4字节对齐,即#pragma pack(4)
    |c2| - | - | - |
    | i            |
    3*4 =12 字节
    
    CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是2^i字节数(i=0,1,2,3…)。
    从CPU的读取性能和效率来考虑,若读取的数据未对齐,则需要两次总线周期来访问内存,因而效率会大打折扣。
    某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常。
    
    struct TestStruct2
    {
         char c1;  // 1字节   
         char c2;  // 1字节
         short s;  // 2字节
         int i;    // 4字节
    }
    
    |c1|c2|s    |
    |i          |
    2*4 = 8字节内存
    
    
    使用指令#pragma pack (n),编译器将按照 n 个字节对齐。
    使用指令#pragma pack (),编译器将取消自定义字节对齐方式。
    在#pragma pack (n)和#pragma pack ()之间的代码按 n 个字节对齐。
    
    
    #pragma pack(8)
    struct TestStruct4
    {
         char a; // 1字节
         long b; // 4字节
    };
    struct TestStruct5
    {
         char c;  // 1字节
         TestStruct4 d; 
         long long e;// 8字节
    };
    #pragma pack()
                             a    b
    TestStruct4 的内存布局: 1***,1111,
                            c   TestStruct4.a TestStruct4.b   d
    TestStruct5 的内存布局: 1***,   1***,      1111, ****, 11111111
    

    6. 函数指针类型

    void(*)() , 指向类型为 void (void)的函数的 函数指针
    (void(*) ())0 ,将 0 强制转换为函数指针类型, 0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。
    (*(void(*) ())0),取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。
    (*(void(*) ())0)(), 这是函数调用
    同理 :
    (*(char**(*) (char **,char **))0) ( char **,char **);
    char * (*pf)(char * p);   // 定义的是一个函数指针 pf, 指向一个类型为 char*(char*)的函数
    char * (*pf[3])(char * p);// 定义一个 函数指针 数组, 数组名为 pf,数组内存储了 3 个指向函数的指针。
    char * (*(*pf)[3])(char * p);// 定义一个指针,指向一个函数指针数组,该数组内存放3个 指向类型为char*(char*)的函数的函数指针。
    

    7. 文档说明

    /************************************************************************
    * File Name : FN_FileName.c/ FN_FileName.h                      文件名
    * Copyright : 2003-2008 XXXX Corporation,All Rights Reserved.   版权亦称“著作权”
    * Module Name : Draw Engine/Display                             文件模块功能名称
    *
    * CPU : ARM7
    * RTOS : Tron
    *
    * Create Date : 2008/10/01                                      创建日期
    * Author/Corporation : WhoAmI/your company name                 作者
    *
    * Abstract Description : Place some description here.           文件描述信息
    *
    *-----------------------Revision History----------------------- 版本信息
    * No Version Date Revised By Item Description
    * 1 V0.95 08.05.18 WhoAmI abcdefghijklm WhatUDo
    *
    ************************************************************************/
    

    <内容来自网络,如有侵权,请立即联系本人,自当立即删除>

  • 相关阅读:
    combo,raido
    块级作用域问题ES5 & ES6
    基本类型和引用类型_深拷贝和浅拷贝
    由数组扁平化切入generator函数
    Promise基本用法
    原生ajax请求之前端
    ExtJS组件window
    ORACLE(+) 号的用法,及与逗号运算符的差别
    centos7发布json中文显示乱码
    centos7 svn在repository在的情况下重装恢复
  • 原文地址:https://www.cnblogs.com/bacmive/p/11315227.html
Copyright © 2020-2023  润新知