精华内容
下载资源
问答
  • 今天遇到一个问题,一个很大的结构体需要分两次使用串口将结构体数据发送出去,第一次发送很简单,第二次的起始地址需要跳转到结构体的中间,方法很多,比如第二次从结构体的某个元素开始,name可以取该元素的地址,...

    今天遇到一个问题,一个很大的结构体需要分两次使用串口将结构体数据发送出去,第一次发送很简单,第二次的起始地址需要跳转到结构体的中间,方法很多,比如第二次从结构体的某个元素开始,name可以取该元素的地址,或者将结构体内容拷贝到一个char数组内,然后使用数组索引定位第二次发送的起始地址,但这两种方法我都不满意,网上查找了一下可以使用指针加强制转换,:


    #include<stdio.h>

    struct Test{
        char Item1;
        char Item2;
        char Item3;
        char Item4;
        char Item5;
        char Item6;    
    };

    int main(){

        struct Test TestStr;
        char *Ptr;

        TestStr.Item1 =1;
        TestStr.Item2 =2;
        TestStr.Item3 =3;
        TestStr.Item4 =4;
        TestStr.Item5 =5;
        TestStr.Item6 =6;
        //强制转换成char指针
        Ptr = (char *)&TestStr;
        printf("Ptr +0 = %d\r\n" ,*(Ptr +0));
        printf("Ptr +1 = %d\r\n" ,*(Ptr +1));
        printf("Ptr +2 = %d\r\n" ,*(Ptr +2));
        printf("Ptr +3 = %d\r\n" ,*(Ptr +3));
        printf("Ptr +4 = %d\r\n" ,*(Ptr +4));
        printf("Ptr +5 = %d\r\n" ,*(Ptr +5));
       
        return 0;
    }

    展开全文
  • 大中小C语言结构体详解2018-01-20大家都知道学习嵌入式培训讲师东哥为大家带来关于:C语言结构体详解,希望能帮助到更多的嵌入式学习者。1 概述C语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合...

    7eb3e0672a919999a084342368b079a6.png

    0cc6569450afffd4f975b5309e397c0a.png

    0cc6569450afffd4f975b5309e397c0a.png

    0cc6569450afffd4f975b5309e397c0a.png

    0cc6569450afffd4f975b5309e397c0a.png

    0cc6569450afffd4f975b5309e397c0a.png

    0cc6569450afffd4f975b5309e397c0a.png

    ed8fc638cd806b02029203b45a148a24.png

    C语言中结构体详解

    2018-01-20

    大家都知道学习嵌入式培训讲师东哥为大家带来关于:C语言中结构体详解,希望能帮助到更多的嵌入式学习者。

    1 概述

    C语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,它相当于其它高级语言中记录。

    声明一个结构休类型的一般形式如下:

    struct 结构体名

    {成员列表};

    结构体名,用作结构体类型的标志,它又称 结构体标记,大括号内是该结构体中的各个成员,由它们组成一个结构体,对各成员都应进行类型声明如:

    类型名 成员名;

    也可以把 成员列表称为 域表,第一个成员也称为结构体中的一个域。成员名定名规则写变量名同。

    struct student

    {

    int num;

    char name[20];

    char sex;

    int age;

    float score;

    char addr[30];

    };

    2 定义结构体类型变量的方法

    前面只是指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元,为了能在程序中使用结构类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据,可以采取以下3种方法定义结构体类型变量。

    (1)先声明结构体类型再定义变量名

    如上面已定义了一个结构体类型 struct student,可以用它来定义变量。如:

    struct student  //结构体类型名

    student1, student2//结构体变量名

    定义了 student1, student2 为 struct student 类型的变量。

    在定义了结构体变量后,系统会为之分配内存单元。例如 student1 和 student2在内存中各占59个字节。

    应当注意,将一个变量定义为标准类型(基本数据类型)与定义为结构体类型不同之处在于后者不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型(例如 struct student 类型),因为可以定义出许多种具体的结构体类型。而在定义变量为整形时,只需指定为 int 型即可。

    (2)在声明类型的同时定义变量

    例如:

    struct student

    {

    int num;

    char name[20];

    char sex;

    int age;

    float score;

    char addr[30];

    }student1, student2;

    它的作用与第一种方法相同,即定义了两个 struct student 类型的变量 student1, student2 这种形式的定义的一般形式为

    struct 结构体名

    {

    成员表列

    }变量名表列;

    (3)直接定义结构类型变量

    其一般形式为

    struct

    {

    成员表列

    }变量名表列;

    即不出现结构体名。

    关于结构体类型,有几点要说明:

    a. 类型与变量是不同的概念,不是混同,只能对变量赋值,存取或运算,而不能对一个类型赋值,存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。

    b. 对结构体中的成员(即 域)可以单元使用,它的作用与地位相当于普通变量,

    c. 成员也可以是一个结构体变量。

    如:

    struct date // 声明一个结构体类型

    {

    int month;

    int day;

    int year;

    }

    struct student

    {

    int num;

    char name[20];

    char sex;

    int age;

    struct date birthday;

    char addr[30];

    }student1, student2;

    先声明一个 struct date 类型,它代表 日期 包括3个成员 month, day, year。然后在声明 struct student 类型时,将成员 birthday 指定为 struct date 类型。

    d. 成员名可以与程序中的变量名相同,二者不代表同一对象。

    3 结构体变量的引用

    (1)不能将一个结构体变量作为一个整体进行输入和输出。

    只能对结构体变量中的各个成员分别进行输入输出。引用结构体变量中的成员的方式为

    结构体变量名.成员名

    例如 student1.num 表示 student1 变量中的 num 成员,即 student1 的 num 项,可以对变量的成员赋值。例如:

    student1.num = 10010;

    "." 是成员(分量)运算符,它在所有的运算符中优先级最高,因此可以把 student1.num 作为一个整体来看待。上面的赋值语句作用是将整数 10010赋给 student1 变量中的成员 num。

    (2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。只能对最低的成员进行赋值或存取以及运算。

    例如:结构体变量 student1 可以这样访问各成员:

    student1.num

    student1.birthday.month

    注意,不能用 student1.birthday 来访问 student1 变量中的成员 birthday,因为 birthday 本身是一个结构体变量。

    (3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。

    student2.score = student1.score;

    sum = student1.score + student2.score;

    student1.age ++;

    ++ student1.age;

    由于 "." 运算符的优先级最高,因此 student1.age ++ 是对 student1.age 进行自加运算。而不是先对 age 进行自加运算。

    (4)可以引用结构体变量成员的地址。也可以引用结构体变量的地址。如:

    scanf("%d", &student1.num);// 输入 student1.num 的值

    printf("%o", &student1);// 输出 student1 的首地址

    但不能用以下语句整体读入结构体变量如:

    scanf("%d,%s,%c,%d,%f,%s", &student1);

    结构体变量的地址主要用于作函数参数,传递结构体的地址。

    4 结构体变量的初始化

    和其它类型变量一样,对结构体变量可以在定义时指定初始值。

    如:

    #include

    struct student

    {

    long int num;

    char name[20];

    char sex;

    char addr[30];

    }a = {89031, "Li Lin", 'M', "123 Beijing Road"};

    void main()

    {

    printf("NO. : %d\nname: %s\nsex: %c\naddress: %s\n", a.num, a.name, a.sex, a.addr);

    }

    5 结构体数组

    一个结构体变量中可以存放一组数据(如一个学生的学号,姓名,成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数据值型数组不同之处在于每个数组元素都一个结构体类型的数据,它们分别包括各个成员(分量)项。

    5.1 定义结构体数组

    和定义结构体变量的方法相仿,只需说明其为数组即可。

    struct student

    {

    int num;

    char name[20];

    char sex;

    int age;

    float score;

    char addr[30];

    };

    struct student stu[3];

    以上定义了一个数组 stu,其元素为 struct student 类型数据,数组有 3 个元素。也可以直接定义一个结构体数组。如:

    struct student

    {

    int num;

    ....

    }stu[3];

    struct

    {

    int num;

    ...

    }stu[3];

    5.2 结构体数组的初始化

    与其它类型数组一样,对结构体数组可以初始化如:

    struct student

    {

    int mum;

    char name[20];

    char sex;

    int age;

    float score;

    char addr[30];

    }stu[3] = {{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},

    {10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},

    {10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"}};

    定义数组 stu 时,元素个数可以不指定,即写成以下形式:

    stu[] = {{...},{...},{...}};

    编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。

    当然,数组的初始化也可以用以下形式:

    struct student

    {

    int num;

    ...

    };

    struct student stu[] = {{...},{...},{...}};

    即先声明结构体类型,然后定义数组为该结构体类型,在定义数组时初始化。

    从以上可以看到,结构体数组初始化的一般形式是在定义数组的后面加上:

    5.3 结构体数组应用举例

    下面例子说明结构体数组的定义和引用。

    #include

    #include

    #include

    struct person

    {

    char name[20];

    int count;

    }leader[3] = {{"Li", 0},

    {"Zhang", 0},

    {"Fun", 0}};

    void main()

    {

    int i, j;

    char leader_name[20];

    for(i = 1; i<= 10;i++)

    {

    scanf("%s", leader_name);

    for(j=0;j<3;j++)

    if(strcmp(leader_name, leader[j].name) == 0)

    leader[j].count ++;

    }

    printf("\n");

    for(i=0;i<3;i++)

    printf("%5s: %d\n", leader[i].name, leader[i].count);

    system("pause");

    }

    运行结果如下:

    LI

    Li

    Fun

    Zhang

    Zhang

    Fun

    Li

    Fun

    Zhang

    Li

    Li: 3

    Zhang: 3

    Fun: 3

    6 指向结构体类型数据的指针

    一个结构体变量的指针就是该变量所占据的内存段的起始地址,可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。

    6.1 指向结构体变量的指针

    指向结构体变量的指针的应用:

    #include

    #include

    #include

    struct student

    {

    long num;

    char name[20];

    char sex;

    float score;

    };

    void main()

    {

    struct student stu_1;

    struct student *p;

    p = &stu_1;

    stu_1.num = 89101;

    strcpy(stu_1.name, "Li Lin");

    stu_1.sex = 'M';

    stu_1.score = 89.5;

    printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score);

    printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", (*p).num, (*p).name, (*p).sex, (*p).score);

    system("pause");

    }

    在主函数中声明了 struct student 类型,然后定义了一个 struct student 类型的变量,stu_1 同时又定义一个指针变量 p ,它指向一个 struct student 类型的数据,在函数的执行部分将结构体变量 stu_1 的起始地址赋给指针变量 p ,也就是使 p 指向 stu_1 然后对 stu_1 的各成员赋值,第二个 printf 函数也是用来输出 stu_1 各成员的值,但使用的是 (*p).num 这样的形式, (*p) 表示 p 指向的结构体变量,(*p).num 是 p 指向的结构体变量中的成员 num 。注意 *p 两侧的括弧不可省略,因为成员运算符 '.' 优先于 '*' 运算符,*p.num 就等价于 *(p.num)

    运行结果如下:

    NO. :89101

    name: Li Lin

    sex:M

    score:89.500000

    NO. :89101

    name: Li Lin

    sex:M

    score:89.500000

    可以看到两个 printf 输出的结果相同。

    在C语言中,为了使用方便和使之直观,可以把 (*p).num 改用 p->num 来代替,它表示 *p 所指向的结构体变量中的 num 成员,同样,(*p).name 等价于 p->name。

    也就是说以下三种形式等价:

    a. 结构体变量.成员名

    b. (*p).成员名

    c. p->成员名

    上面的最后一个 printf 函数输了项可以改写为

    printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n",p->num, p->name, p->sex, p->score);

    其中 -> 称为指向运算符。

    分析以下几种运算符

    p -> n 得到 p 指向的结构体变量中的成员 n 的值

    p -> n ++ 得到 p 指向的结构体变量中的成员 n 的值,用完值后使它加1

    ++p -> n 得到 p 指向的结构体变量中的成员 n 的值使之加 1 (先加)

    6.2 指向结构体数组的指针

    以前介绍过可以使用指向数组或数组元素的指针和指针变量,同样,对结构体数组及其元素也可以用指针变量来指向。

    指向结构体数组的指针的应用

    #include

    #inlcude

    struct student

    {

    int num;

    char name[20];

    char sex;

    int age;

    };

    struct student stu[3] = {{10101, "Li Lin", 'M', 18},

    {10102, "Zhang Fun", 'M', 19},

    {10103, "Wang Min", 'F', 20}};

    void main()

    {

    struct student *p;

    printf("No.  name    sex    age\n");

    for(p=stu; p

    printf("%5d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age);

    system("pause");

    }

    运行结果如下:

    No.  name    sex    age

    10101 Li Lin                M     18

    10102 Zhang Fun        M     19

    10103 Wang Min          F      20

    注意以下两点:

    (1)如果 p 的初值为 stu,即指向第一个元素,则 p + 1 后指向下一个元素的起始地址。例如:

    (++p) -> num 先使 p 自加 1 ,然后得到它指向的元素中的 num 成员的值(即10102)。

    (p++) ->num 先得到 p->num 的值(即10101),然后使 p 自加 1 ,指向 stu[1]。

    注意以上二者的不同。

    (2)程序已定义了指针 p 为指向 struct student 类型数据的变量,它只能指向一个 struct student 型的数据(p 的值是 stu 数组的一个元素的起始地址),而不能指向 stu 数组元素中的某一成员,(即 p 的地址不能是成员地址)。例如,下面是不对的:

    p = &stu[1].name

    编译时将出错。千万不要认为反正 p 是存放地址的,可以将任何地址赋给它。如果地址类型不相同,可以用强制类型转换。例如:

    p = (struct student *)&stu[1].name;

    此时,在 p 中存放 stu[1] 元素的 name 成员的起始地址。

    6.3 用结构体变量和指向结构体的指针作函数参数

    将一个结构体变量的值传递给另一个函数,有3个方法:

    (1)用结构体变量的成员作参数,例如:用 stu[1].num 或 stu[2].name 作函数实参,将实参值传给形参。用法和用普通变量作实参是一样的,属于 值传递 方式。应当注意实参与形参的类型保持一致。

    (2)用结构体变量作参数。老版本的C系统不允许用结构体变量作实参,ANSI C取消了这一限制。但是用结构体变量作实参时,采取的是 值传递 的方式,将结构体变量所占的内存单元全部顺序传递给形参。形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元。这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的,此外由于采用值传递方式,如果在执行被调用函数期间改变了形参(也是结构体变量)的值,该值不能返回主调函数,这往往造成使用上的不便。因此一般较少用这种方法。

    (3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。

    用结构体变量作函数参数。

    #include

    #define FORMAT "%d\n%s\n%f\n%f\n%f\n"

    struct student

    {

    int num;

    char name[20];

    float score[3];

    };

    void print(struct student stu)

    {

    printf(FORMAT, stu.num, stu.score[0], stu.score[1], stu.score[2]);

    printf("\n");

    }

    void main()

    {

    struct student stu;

    stu.num = 12345;

    strcpy(stu.name, "Li Li");

    stu.score[0] = 67.5;

    stu.score[1] = 89;

    stu.score[2] = 78.6;

    printf(stu);

    }

    将上面改用指向结构体变量的指针作实参。

    #include

    #define FORMAT "%d\n%s\n%f\n%f\n%f\n"

    struct student

    {

    int num;

    char name[20];

    float score[3];

    }stu = {12345, "Li Li", 67.5, 89, 78.6};

    void print(struct student *p)

    {

    printf(FORMAT, p->num, p->name, p->score[0], p->score[1], p->score[2]);

    printf("\n");

    }

    void main()

    {

    print(&stu);

    }

    赞赏

    f1f51b96aec10983863b826c21c20ae3.png

    f1f51b96aec10983863b826c21c20ae3.png

    f1f51b96aec10983863b826c21c20ae3.png

    f1f51b96aec10983863b826c21c20ae3.png

    共11人赞赏

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。

    展开全文
  • 结构体类型C语言中还有一种类型叫做结构体类型,它是可以保存不同类型数据并且可以把这些不同类型的数据当做一个整体来管理的类型1).结构体的定义语法:struct 结构体名{成员列表;}; 注意:这里是有 分号 的!!成员列表...

    结构体类型

    C语言中还有一种类型叫做结构体类型,它是可以保存不同类型数据并且可以把这些不同类型的数据当做一个整体来管理的类型

    1).结构体的定义

    语法:

    struct 结构体名{

    成员列表;

    };        注意:这里是有 分号 的!!

    成员列表里面写成员。成员的语法格式为:

    类型  成员名;  // 每个成员之间用分号隔开

    例:

    struct girlFriend{

    char name[50]; //姓名

    int age;         //年龄

    char gender[4];//性别

    int height;     //身高

    int weight;     //体重

    char bodyCai;  //身材

    };

    注意:此时写了多个不用类型的成员变量,但是并没有存储数据,只是定义了一个新的数据类型————结构体类型

    2).结构体类型的变量的声明

    结构体的声明语法:

    struct 结构体名 变量名;

    注意:struct和结构体名合起来才叫一个类型,就比如说int *一样由int和*合起来才算一个指针类型

    例:

    struct girlFriend gf;  // gf就是变量名,struct girlFriend是类型

    3).结构体的初始化和赋值

    语法1:

    结构体类型 结构体变量名 = { 成员数据1,成员数据2,....成员数据n };

    例:struct girlFriend fj = { "小红",16,"女",155,45,'O' };

    语法2:

    结构体类型  结构体变量名 =  { .成员名 = 数据1,.成员名2 = 数据2.....  };

    例:struct girlFriend fr = { .gender = "女",.height=155,.name="小红",.bodyCai='S',.weight = 80,.age=67  };

    语法3:结构体变量,也允许先声明,后一次性赋值

    例:struct girlFriend fj;

    fj = (struct girlFriend){ "小红",16,"女",155,45,'O' };

    4).结构体的取值

    语法: 结构体变量名.成员名;

    例: fj.age;

    fj.name;

    注意:没有任何的格式化控制符能帮你一下子输出结构体变量的值

    5).结构体其他的一些细节

    1.结构体类型可以定义在函数内,也可以定在函数外

    如果定义在函数外,那么从它定义的位置开始,直接到文件结束,都可以使用到这个类型

    如果定义在函数内,那么它的作用范围只能从它定义的位置开始,直到它所在的代码块结束

    2.可以在定义结构体类型的时候,就声明这个结构体类型的变量

    例:

    struct student{

    char *name;

    int age;

    int gender;

    }s2;  //这个s2就是这个结构体的变量

    如果要同时声明多个变量,那么以,隔开

    例:

    struct student{

    char *name;

    int age;

    int gender;

    }s2,s3,s4;

    3.可以定义一个匿名的结构体,一般都会在定义匿名结构体的时候就声明它的变量,否则没有任何意义

    例:

    struct{

    int year;

    int month;

    int day;

    }day1;  //day1就是这个匿名结构体的变量

    6).typedef与结构体搭配使用

    声明结构体变量的语法:

    struct 结构体名 变量名;

    类型,有2个单词

    int num;

    char ch;

    float f;

    struct student s1;

    用typedef就可以用一个关键字来声明结构体变量

    语法:

    typedef struct{

    成员列表;

    }类型名;

    例:

    typedef struct {

    char *name;

    int age;

    int gender;

    }Student; //因为前面加了typedef,所以此处的Student不是变量,而是类型

    展开全文
  • [流畅的 C] C语言结构体转化为字符串本文并非标题的具体实现。而是提供一种编程方式,习惯,一种探讨。本文有一点点门槛,有 socket,开源协议栈学习/开发经验者阅读更佳。Overview[*流畅的 C*] C语言结构体转化...

    [流畅的 C] C语言将结构体转化为字符串

    本文并非标题的具体实现。而是提供一种编程方式,习惯,一种探讨。

    本文有一点点门槛,有 socket,开源协议栈学习/开发经验者阅读更佳。

    Overview

    [*流畅的 C*] C语言将结构体转化为字符串

    思路

    struct (packet) to string “抽象实现”

    如何使用

    全文亮点

    Reference

    a6c6504acadc79deec3c780782e7e5e1.png

    思路

    直接使用 memcpy 之类的是不会得到你期望的。

    所以最好的做法就是定义结构体的时候就实现对字符串的转换。

    就像 Python 的 __str__ 一样。

    (不好意思,博主雷打不动转python!信仰上帝Python)

    如果不懂 python 也没有关系,我在下面会说明 C 语言的方法。

    假设你有一个 packet:

    struct protocol_packet { /* 假设 open source 已经帮你把字节码翻译成 ACSII / HEX 完成*/

    unsigned char Mac[16];

    unsigned char IPv4Addr[64];

    };

    然后你你在一个 open source 代码中,有个函数,传递了接受过来的packet:

    int

    I_am_open_source_handler(struct protocol_packet *recv_packet){

    // ...do things...

    return 0;

    }

    struct (packet) to string “抽象实现”

    这个时候你想把 packet 打印出来看看里面有什么。

    我们可以这么做:

    免责声明,因为个人时间有限,没有对以下纯手打抽象出来的代码实验,

    但是思路不会错,所以具体细节还需要看官自己微调一下。

    struct protocol_packet { /* 假设 open source 已经帮你把字节码翻译成 ACSII / HEX 完成*/

    unsigned char Mac[16];

    unsigned char IPv4Addr[64];

    int (*packet2str)(char*, struct protocol_packet*);

    int (*spacket2str)(char*, struct protocol_packet*, size_t);

    };

    int protocol_packet2str(char dstStr[], struct protocol_packet *recv_packet){

    /** why char dstStr[]?:

    * 这个和 char *dstStr, 是完全一样的,这些写只是为了方面了解含义。

    * 实际上它不是数组,关键词:“指针退化”

    * 我会假设你知道 *recv_packet 这么传递有助于提升运行效率;

    * 如果你对 const 熟悉,我建议“像强迫症”一样给它加上 const,

    * 因为这样能够说明本函数不会改变 recv_packet 的内容。

    *

    * 你无法直接拷贝整个 struct 成为你想要的 string,

    * 因为有些成员可能是 HEX 之类的,输出时会有问题,

    * 所以只能针对它内部的成员一个一个拷贝;

    * 因为是用来输出的,所以这个时候你可以直接添加一些字段的含义说明在 dstStr 中

    */

    unsigned char mapping_struct_Mac[16];

    unsigned char mapping_struct_IPv4Addr[64];

    /* 假设 open source 已经将 MAC 解析成了 FF0073E4FFFF 的形式*/

    memcpy(mapping_struct_Mac, recv_packet->Mac, 16);

    memcpy(mapping_struct_IPv4Addr, recv_packet->IPv4Addr, 64);

    /** 现在你可以使用 snprintf() 定制你的字符串输出了

    * 注意, MAC 不能使用 '%s' 的方式, 你得 for 循环 使用 %x(%X), 再注意,MAC 不是 16 byte 长度!

    * 为了避免误导,因为我主要的时间都在写 Python,所以C语言没有测试可能会有错误,

    * 因此下面不给实例,要你自己实现 snprintf() 的具体内容,这里是思路:

    * 比如针对 MAC: 01234 */

    snprint(dstStr, 5, "MAC: "); /* 有没有人能教我一些 C 语言里面计算偏移的技巧??? */

    snprint(&dstStr[5], 18, "%02X:%02X:%02X:%02X:%02X:%02X",

    mapping_struct_MAC[0], mapping_struct_MAC[1], mapping_struct_MAC[2],

    mapping_struct_MAC[3], mapping_struct_MAC[4], mapping_struct_MAC[5]);

    // ...do the final job by you....

    return 0;

    }

    int sprotocol_packet2str(char dstStr[], struct protocol_packet *recv_packet size_t length_of_dstStr){

    /** 你可以实现一个 safe 版本,比起上面,只是多了一个 dstStr 的长度检查; */

    return 0;

    }

    如何使用

    这里有一处必须要注意的地方:

    因为我们上面把 struct 里面的内容改了,增加了一个转化为 string 的函数指针(还有一个 option 的 safe 方法),

    但是如果不给这个指针赋值,它是 NULL 的,不能乱用。

    所以,使用的时候,找到 code 里面初始化 recv_packet 的地方,我假设原本 code 是这样的:

    int

    main(...你懂的...){

    struct protocol_packet recv_packet;

    // make me as daemon, come on!

    while(1) { /* loop until universe collapses */

    // 收到 frame -网络字节码-> theFrame

    拆包func(&recv_packet, &theFrame, /*..other if needed..*/);

    I_am_open_source_handler(&recv_packet);

    // ..other if needed...

    }

    return 0;

    }

    那么这个位置我们只需要轻轻一改:

    int

    main(...你懂的...){

    struct protocol_packet recv_packet;

    // make me as daemon, come on!

    while(1) { /* loop until universe collapses */

    // 收到 frame -网络字节码-> theFrame

    拆包func(&recv_packet, &theFrame, /*..other if needed..*/);

    recv_packet.packet2str = protocol_packet2str; // LOOK AT ME !!!!!!!!

    I_am_open_source_handler(&recv_packet);

    // ..other if needed...

    }

    return 0;

    }

    终于到了最后:

    现在你就可以在任何嵌套在 I_am_open_source_handler() 里面很深层次的函数里面这么使用了:

    int

    I_am_open_source_handler(struct protocol_packet *recv_packet){

    // ...do things...

    switch([...]){

    case [...]:

    [...]

    case [...]:

    i_am_a_func_in_the_HANDLER(recv_packet);

    [...]

    break;

    }

    return 0;

    }

    int

    i_am_a_func_in_the_HANDLER(struct protocol_packet *recv_packet_p){

    // 我想要在这里知道 recv_packet 内部具体有哪些值,

    // OK, that's do it:

    char my_add_debug_str[2048] = {'\0'}; /* 长一点总不会坏事吧 */

    recv_packet_p->packet2str(my_add_debug_str, recv_packet_p); /* 注意,这里 recv_packet_p 是指针类型哦 */

    printf("%s", my_add_debug_str); /* 看,这样就可以愉快地输出了 */

    /* 当我知道了 protocol 里面有哪些内容之后,

    * 我可能会在下面的 source code 前面的现在这里,

    * 添加一些自己的代码,做一些检查,定制化等等。

    */

    // ..do magic things...

    // BUT, I don't care this part code!

    }

    全文亮点

    当然,你可以定义一个全局函数,不修改 struct protocol_packet 里面的内容,全局函数就跟 protocol_packet2str() 里面一样写就可以了。然后需要的地方,直接调用这个全局函数。

    但是这样写还要知道这个函数不是吗?

    在产品代码里面,这个函数一般都不会出现在像上面的 i_am_a_func_in_the_HANDLER() 这样的具体行为的代码里面,但是,如果定义了这样一个自动转化的指针,那么每个结构体初始化的位置: struct protocol_packet recv_packet; 你都可以给它绑定函数:

    recv_packet.packet2str = protocol_packet2str; // LOOK AT ME !!!!!!!!

    这个绑定语句可以紧跟在初始化位置后面,不用在上面的 while 循环之类的内部绑定即可。上面是为了方面理解。

    这句代码可以留着,因为给结构体的一个成员绑定一个地址并不会消耗什么资源,并且它不会有任何输出。

    考虑如下的情况:

    当另外一个人,完全没有接触过这个代码,或者说,

    你自己几个月之后又要跟踪 packet 的状态,

    然后你很不巧地发现自己当初写的结构体成员(变量)名称含义不明 – 看到 struct 内部脑海里就出现黑人问号…

    那么当你看到这样一个结构体:

    struct protocol_packet { /* 假设 open source 已经帮你把字节码翻译成 ACSII / HEX 完成*/

    unsigned char i_am_not_named_mac_addr[16];

    unsigned char i_have_a_strange_name[64];

    int (*packet2str)(char*, struct protocol_packet*);

    int (*spacket2str)(char*, struct protocol_packet*, size_t);

    };

    你就知道可以这么调用:

    recv_packet_p->packet2str(debug_str, recv_packet_p);

    来的得到整个结构体内部变量的值是怎么样的了,然后很轻松地把它打印显示出来。

    非指针是这么调用: recv_packet.packet2str(debug_str, &recv_packet) ;

    于是你就可以很自然地写出这三行代码:

    char debug_str[2048] = {'\0'};

    recv_packet_p->packet2str(debug_str, recv_packet_p);

    printf("%s", debug_str);

    从此观察结构体内部状态就变成了一个很轻松地事情了。

    一般我们可能只是要个输出,那么完全可以定义一个

    void (*packet_format_print)(struct protocol_packet*); 在结构体内部,

    只不过这个方法可能不足够安全,因为一些系统知识有关的原因,在这个函数内部的实现输出根据不同的平台需要做一个适配的调整。比如输出到文件/syslog?输出到默认终端?输出到 console? 是指这个意思。

    在初始化结构体的时候绑定函数,就是基于对象的做法,类似 C++ 有个构造函数。

    struct 可以当作一个 default public 的类来使用,所以只要自己定义好了构造函数,在 C 里面也是可以很方便的直接初始化它,而不用上述显式地去绑定函数。

    但是这部分说明,对于这个字符串化结构体这个主题,相关性不大。所以这里只是一个提及。

    Reference

    实际上这里没有啥 reference, 但是如果你觉的上面的内容有用,有些内容不理解?,想要多了解一下?

    那么这里有一些是上面内容使用到的知识点:

    指针退化;

    C 语言的基于对象编程(编程范式)-> 使用函数指针实现对象“方法”;

    ACSII 码可以 %s,查看,HEX 码万万不能误用 %s 来输出;

    daemon 进程一般程序内部使用 printf 不会输出到终端;

    一些一时说不上来的细节。

    快点学 python 吧!

    欢迎朋友指出上面文章内容的错误之类。

    或者有更好的建议。

    本人水平有限,本文仅供参考。

    展开全文
  • 定义和使用结构体变量自己建立结构体类型用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体声明一个结构体类型的一般形式为:struct 结构体名{ 成员表列 };**************************struct Student...
  • C语言结构体和共用体.ppt11 1概述 C语言的数据类型 基本类型 intcharfloatdouble指针类型构造类型 数组 结构体 共用体枚举类型空类型void 结构体 structure 是一种数据类型 它把互相联系的数据组合成一个整体 例 ...
  • C语言结构体直接赋值?

    万次阅读 多人点赞 2018-10-21 10:47:29
    C语言结构体变量之间可以进行赋值操作吗? 简单结构体的赋值 先说结论:一般来说,C语言中的结构体变量可以用另一个变量对其进行赋值或初始化。简单结构体(不包含指针成员)直接赋值没有问题。 我们先下面一...
  • 《第8章C语言结构体和共同体.ppt》由会员分享,可在线阅读,更多相关《第8章C语言结构体和共同体.ppt(41页珍藏版)》请在皮匠网上搜索。1、1第八章结构体、共用体和枚举类型8.1结构体8.2共用体8.3枚举类型8.4用...
  • 为此,环球网校小编为大家整理了2019年计算机二级C语言考点结构体相关信息,希望能够帮助到大家,了解更多计算机二级考试相关信息敬请关注环球网校。结构体类型的说明结构体是若干个类型数据的集合,结构体类型说明...
  • C语言 | 结构体指针

    千次阅读 2021-05-06 08:52:44
    C语言指向结构体变量的指针 在C语言中,指向结构体对象的指针变量既可以指向结构体变量,也可指向结构体数组中的元素。 指针变量的基类型必须与结构体变量的类型相同。 C语言中允许 (*p).num用p->num来代替 -&...
  • C语言结构体

    2021-01-17 22:25:29
    C语言中的结构体 一、为什么要用结构体? 1、背景:例如输出一个学生成绩的最高分最低分,但是最高分那个同学的其他信息如何获取呢? 答:这样就利用了结构体,把多个变量放在结构体中。 2、数组和结构体区别? 数组...
  • 结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针。html指向结构体变量的指针前面咱们经过“结构体变量名.成员名”的方式引用结构体变量中的成员,除了这种方法以外还能够使用指针。前面讲过,&...
  • C语言-结构体

    2020-02-03 21:33:32
    C语言-结构体结构体定义结构体变量1、结构体变量的定义和初始化1结构体变量的定义2结构体变量的初始化2、结构体变量的引用1对结构体变量整体的引用2对结构体变量成员的引用 结构体定义 struct st_type //st_type为...
  • C语言结构体和共同体第八章 结构体、共用体和枚举类型 结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体-------自定义数据类型 先定义结构体类型,再定义结构体变量 一般形式: 定义结构体类型的...
  • 用户自己建立自己的结构体类型1、 定义和使用结构体变量(1)、结构体的定义C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体。(2)、声明一个结构体类型的一般形式为:Struct 结构体名{ 成员...
  • C语言结构体对齐问题总结
  • C语言结构体实现一个通讯录,通讯录可以用来存储1000个人的信息,每个人的信息包括: 姓名、性别、年龄、电话、住址 提供方法: 1. 添加联系人信息 2. 删除指定联系人信息 3. 查找指定联系人信息 4. 修改指定联系...
  • 结构体的sizeof这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:struct s1{char c;int i;};问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就...
  • 六、结构体的使用1.一般对结构体变量的操作是以成员为单位进行的,引用的一般形式为:结构体变量名.成员名1 struct Student {2 char *name;3 int age;4 };56 struct Student stu;78 // 访问stu的age成员9 stu.age = ...
  • c语言结构体)---实现学生信息输入,输出,查询

    万次阅读 多人点赞 2017-11-10 15:05:10
    c语言结构体)---实现学生信息输入,输出,查询 利用结构体实现学生信息的输入,输出,以及生日日期查询 #include #define NUM 3 //日期结构体 typedef struct{ int year; int month; int day; }DATE; ...
  • C语言结构体1. 结构体是什么?2. 结构体怎么用?2.1 定义结构体2.2 定义结构体变量2.3 结构体成员引用2.5 结构体成员赋值2.6 结构体赋值2.7 结构体整体初始化2.8 结构体部分初始化3. 其他语法3.1定义结构体并同时...
  • C语言结构体

    2021-04-30 11:15:05
    不能将一个结构体变量作为一个整体机型输入和输出 结构体变量的地址主要作用于函数参数,传递结构体变量的地址 1. 定义 struct 结构体名{ 成员列表 }; 例如: struct student{ int ID; char name[20]; int age...
  • Day07 郝斌C语言自学视频之C语言结构体结构体为什么需要结构体什么叫结构体如何去定义结构体怎样使用结构体变量结构体变量和结构体指针作为函数参数传递的问题结构体变量的运算动态构造存放学生信息的结构体数组...
  • c语言结构体

    2017-11-26 22:28:55
    C语言中的结构体——>C语言的实体 1.结构体概念  2. 结构体声明  3. 结构体定义  5. 结构体变量成员的引用  6. 结构体变量的赋值  7. 结构体变量的初始化  8. 结构体的嵌套 结构体的概念: ...
  • C语言-结构体成员遍历 此方法试用的前提:结构体成员的数据类型相同 。话不多说,直接上手。 “结构体成员遍历”进阶版:当结构体里的成员数据类型不一样,可以计算出每个结构体成员的偏移量,并将偏移量放到一个...
  • C语言结构体详解

    2014-06-17 14:37:14
    C语言结构体详解 时间:2013-02-20 16:06来源:凌阳教育 作者:larran 点击:1030次  大家都知道学习嵌入式开发,首先要学的一门重要的语言就是c语言,所以大家在c语言学习中一定要谨慎对待,每个...
  • C语言笔记 结构体

    2019-11-24 18:40:35
    结构体的定义 第一种:只对结构体进行声明 struct 结构体名 { 成员列表 }; struct Student { int num; char name[20]; int age; }; 第二种:在声明类型时同时定义变量 struct 结构体名字 { 成员列表; }...
  • 一起学习C语言结构体(一)> 中,我们了解了结构体的概念与定义形式,以及结构体变量初始化赋值。本章节,我们分析结构体成员访问形式,以及结构数组使用的场景。 章节预览: 4. 结构成员访问 5. 结构数组 目录...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 61,414
精华内容 24,565
关键字:

c语言输出结构体

c语言 订阅