C语言结构体声明中冒号的使用(占位符) & C结构体的乱序初始化

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位 域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名

{ 位域列表 };

其中位域列表的形式为: 类型说明符 位域名:位域长度

例如:

struct bs
{
int a:8;
int b:2;
int c:6;
};

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

struct bs
{
int a:8;
int b:2;
int c:6;
}data;

说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:

1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

struct bs
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*从下一单元开始存放*/
unsigned c:4
}

在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

struct k
{
int a:1
int :2 /*该2位不能使用*/
int b:3
int c:2
};

从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

又:

1:指针类型变量不能指定所占的位数

2. 在声明成员变量时,可以用         变量名 :bit数;

来确定结构体类型的成员变量的值所占的字位数,如果在实际应用中,该变量的值超出了在声明它时所声明的字位数,那么溢出的部分将会丢失。

例子:

#include <cstdlib>
#include <iostream>

using namespace std;

struct BitVariable {
       unsigned a:2;
       unsigned b:3;
       unsigned :0;
       unsigned c:6;

       } BitVariable1;

int main(int argc, char *argv[])
{
    BitVariable BV1;
    BV1.a=2;   //10
    BV1.b=8;   //1000
    BV1.c=86;  //1010110 

    cout<<BV1.a<<endl;  //output 2  <===> 10B
    cout<<BV1.b<<endl;  //output 0  <===> 1000B
    cout<<BV1.c<<endl;  //output 22 <===> 10110B
    cout<<sizeof(BitVariable)<<endl; //output 8. int 32位机器占4字节。 如果将unsigned :0;去掉,则此处输出4。

    system("PAUSE");
    return EXIT_SUCCESS;
}

结构体的乱序初始化

typedef struct _data_t {
    int a;
    int b;
}data_t;

data_t data = {
   .a = 10,
   .b = 20,
};

通常初始化一个结构体的方式是按序初始化,形如:data_t data={10,20}。感觉很好奇,如是上网百度一下,发现linux下struct初始化可以采用顺序和乱序两种方式,而乱序又有两种不同的形式。本文总结一下struct两种初始化方式的优缺点,并给出完整的测试程序。

2、顺序初始化

  教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式。顺序初始化struct必须要按照成员的顺序进行,缺一不可,如果结构体比较大,很容易出现错误,而且表现形式不直观,不能一眼看出各个struct各个数据成员的值。

3、乱序初始化

  乱序初始化是C99标准新加的,比较直观的一种初始化方式。相比顺序初始化而言,乱序初始化就如其名,成员可以不按照顺序初始化,而且可以只初始化部分成员,扩展性较好。linux内核中采用这种方式初始化struct。

  乱序初始化有两种方式,一种是用点(.)符号,一种是用冒号(:)。方式1是C99标准,方式2是GCC的扩展,强烈建议使用第一种方式。

4、测试程序

/*********************************
 * linux下C语言结构体初始化方法
 * @author  Anker  @date:2014/02/11
 * *******************************/

#include <stdio.h>

//函数指针
typedef int (*caculate_cb)(int a, int b);
//结构体定义
typedef struct _oper {
    int a;
    int b;
    caculate_cb cal_func;
} oper;
//加法函数定义
int add(int a, int b)
{
    return (a+b);
}

int main()
{
    int ret = 0;
    //顺序初始化结构体1
    oper oper_one = {10, 20, add};
    //乱序初始化结构体2
    oper oper_two = {
        .b = 30,
        .a = 20,
        .cal_func = &add,
    };
    //乱序初始化结构体3
    oper oper_three = {
         cal_func:&add,
         a:40,
         b:20,
    };
    ret = oper_one.cal_func(oper_one.a, oper_one.b);
    printf("oper_one caculate: ret = %d\n", ret);
    ret = oper_two.cal_func(oper_two.a, oper_two.b);
    printf("oper_two caculate: ret = %d\n", ret);
    ret = oper_three.cal_func(oper_three.a, oper_three.b);
    printf("oper_three caculate: ret = %d\n", ret);
    return 0;
}

测试结果如下图所示:

 参考  http://www.cnblogs.com/Anker/p/3545146.html

时间: 2024-10-12 20:00:54

C语言结构体声明中冒号的使用(占位符) & C结构体的乱序初始化的相关文章

Mybatis 中 sql 语句的占位符 #{} 和 ${}

#{} 表示一个占位符号,通过 #{} 可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换.#{} 可以有效防止   sql注入.#{} 可以接收简单类型值或 pojo 属性值. 如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称. ${} 表示拼接sql串,通过 ${} 可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,不能防止 sql 注入问

13 类对象的声明中加小括号{}和不加小括号{}的区别

以下代码有什么问题? struct Test { Test( int ) {} Test() {} void fun() {} }; void main( void ) { Test a(1); a.fun(); Test b(); b.fun(); } A b.fun()会出错 B Test结构的定义中应该加上public修饰符,才能main函数值调用该类的方法 C Test(int) {}改成Test(int a) {} D 以上说法都错误 解答: b.fun();   //b不是Test的

boost在lambda表达式中调用占位符参数的成员函数的方法

boost中提供了lambda表达式的用法,但是lambda表达式的功能还不是很强大,在其中只能对lambda的占位符参数_1等使用最基本的操作符,如+-*/,可是很多时候如果传入的占位符参数是一个对象指针的话,我们可能想要调用这个类的成员函数. 我在开发中遇到了这个问题,需要在stl的算法中传入一个函数来调用对象的比较函数,因为感觉这样太麻烦,还需要重新定义一个函数,所以想起了lambda表达式,c++11的lambda表达式我倒是没试过,可是受项目开发环境所限,只能选择boost.但是我用的

c语言 struct结构体的变量声明加冒号

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可. 为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为"位域"或"位段".所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数.每个域有一个域名,允许在程序中按域名进行操作.这样就可以把几个不同的对象用一个字节的二进制位域来表示. [1]定义: struct 位域结构名 { 位

c语言:通过指向结构体变量的指针变量输出结构体变量中成员的信息

通过指向结构体变量的指针变量输出结构体变量中成员的信息. 解:程序: #include<stdio.h> #include<string.h> int main() { struct Student { long int num; char name[20]; char sex[10]; float score; }; struct Student stu_1;//定义struct Student类型的变量stu_1 struct Student *p; p = &stu_

【C语言】用结构体数组指针完成:有三个学生信息,存放在结构体数组中,要求输出全部信息

//用结构体数组指针完成:有三个学生信息,存放在结构体数组中,要求输出全部信息 #include <stdio.h> struct Stu { int num; char name[20]; char sex; int age; }; int main() { struct Stu student[3]={{317,"han",'m',20},{318,"hun",'w',22},{311,"dan",'w',18}}; struct

关于结构体声明的一些写法

关于结构体声明的一些写法:第一点:#include<stdio.h>struct square{ int (*add)(int a,int b);};int square_add(int a,int b){ return a + b;} int main(){ struct square stu={ .add=square_add, }; //与下面无区别 stu.add=square_add; return 0;} 第二点:位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一

C语言开发函数库时利用不透明指针对外隐藏结构体细节

1 模块化设计要求库接口隐藏实现细节 作为一个函数库来说,尽力减少和其调用方的耦合,是最基本的设计标准.C语言,作为经典"程序=数据结构+算法"的践行者,在实现函数库的时候,必然存在大量的结构体定义,接口函数需要对这些结构体进行操作.同时,程序设计的模块化要求库接口尽量少的暴露其实现细节,接口参数尽量使用基本数据类型,尽量避免在形参中暴露库内结构体的定义. 2 隐藏结构体的两种方法 以笔者粗浅的认识,有两种最常用的方法,可以实现库内结构体定义的隐藏:接口函数形参使用结构体指针,接口函数

编程题:对结构体变量中成员的引用展示。

编程题:对结构体变量中成员的引用展示. #include<stdio.h> void main() { struct person { char name[20]; char sex; struct date {int year; int month; int day; }birthday; float height; }per; printf("Enter the name:"); gets(per.name);per.sex='M'; per.birthday.year