C 开发学习 - 结构类型(枚举/结构/类型定义)

本文详细介绍了C语言中的枚举与结构的概念、语法及应用案例,包括自动计数枚举、指定值枚举、结构体声明与初始化、结构成员访问、结构指针使用、结构作为函数参数等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、枚举

定义:枚举是 一种用户定义的数据类型,它用的关键字 enum
           枚举类型名字通常并不真的使用,要用的是在大括号里地名字,因为它们就是常量符合,它们的类型是int,值则依次从0到n。
    enum colors {red, yellow, green}
语法:enum 枚举类型名称{名字0m, ..., 名字n};
案例一:自动计数的枚举
//
//  main.c
//  enum
//
//  Created by liuxinming on 15/4/26.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

enum COLOR {RED, YELLOW, GREEN, NumCOLORS};

int main(int argc, const char * argv[]) {
    int color = -1;
    char *ColorNames[NumCOLORS] = {
        "red", "yellow", "green"
    };
    char *colorName = NULL;
    
    printf("输入你喜欢的颜色代码:");
    scanf("%d", &color);
    
    if(color >= 0 && color < NumCOLORS){
        colorName = ColorNames[color];
    }else{
        colorName = "unknown";
    }
    
    
    printf("你喜欢的颜色是%s\n", colorName);
    return 0;
}

案例二:枚举量
声明枚举量的时候可以指定值,enum COLOR{RED=1, YELLOW, GREEN=5}

二、结构

结构是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。 
结构中可以使用不同的数据类型。 

申明结构的形式

struct point{
  int x;
  int y;
}

struct point p1, p2; #p1和p2都是point,里面有x和y的值

struct {
  int x;
  int y;
}p1, p2;
#p1和p2都是一种无名结构,里面有x和y的值

结构变量

struct point p; #p就是一个结构变量
p.x = 12;
p.y = 20;

案例一:使用结构体

//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

//声明结构类型
struct date{
    int month;
    int day;
    int year;
};


int main(int argc, const char * argv[]) {
    
    //结构变量&使用
    struct date today;
    today.month = 04;
    today.day = 12;
    today.year = 2015;
    
    printf("Today is date is  %i-%i-%i.\n",today.year, today.month, today.day);
    
    
    return 0;
}


案列二:结构的初始化

//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

//声明结构类型
struct date{
    int month;
    int day;
    int year;
};


int main(int argc, const char * argv[]) {
    
    struct date today = {04, 26, 2015};
    struct date thismonty = {.month = 4, .year = 2015};
    
    printf("Today is date is  %i-%i-%i.\n",today.year, today.month, today.day);
    printf("This month is  %i-%i-%i.\n", thismonty.year, thismonty.month, thismonty.day);
    
    return 0;
}

输出:
Today is date is 2015-4-26.
This month is 2015-4-0.

结构成员

 * 结构和数组有点像 【数组里有很多单元,结构里有很多成员
 * 数组用[]运算符和下标访问其成员 
   a[0] = 10;
 * 结构用.运算符和名字访问其成员
   today.day
 

结构运算

 * 要访问整个结构,直接用结构变量的名字
 * 对于整个结构,可以做赋值、取地址、也可以传递给函数参数
   p1 = (struct point) {5, 10} // 相当于p1.x = 5 p1.y = 10;
   p1 = p2; // 相当于p1.x = p2.x ; p1.y = p2.y;

结构指针

 * 和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
 * struct date *pDate = &today;
 
//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

//声明结构类型
struct date{
    int month;
    int day;
    int year;
};


int main(int argc, const char * argv[]) {
    
    struct date today;
    
    today = (struct date){04, 26, 2015};
    
    struct date day;
    
    struct date *pDate = &today;
    
    printf("Today's date is %i-%i-%i.\n", today.year,today.month,today.day);
    printf("The day's date is %i-%i-%i.\n", day.year, day.month, day.day);
    printf("address of today is %p\n", pDate);
    
    return 0;
}
输出:
Today's date is 2015-4-26.
The day's date is 0-1606416456-32767.
address of today is 0x7fff5fbff7f0
Program ended with exit code: 0

结构作为函数参数

int numberOfDays(struct date d)
* 整个结构可以作为参数的值传入函数
* 这时候是在函数内新建一个结构变量,并复制调用者的结构的值
* 也可以返回一个结构
案例:输入今天日期 ,输出明天日期【主要介绍结构体用法,不具体说明实现过程,想了解的自己研究下】
//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>
#include <stdbool.h>

//声明结构类型
struct date{
    int month;
    int day;
    int year;
};

bool isLeap(struct date d);//判断是否为闰年
int numberOfDays(struct date d);


int main(int argc, const char * argv[]) {
    
    struct date today, tomorrow;
    
    printf("Enter today's date(mm dd yyyy):");
    scanf("%i %i %i", &today.month, &today.day, &today.year);
    
    if(today.day != numberOfDays(today)){
        tomorrow.day = today.day + 1;
        tomorrow.month = today.month;
        tomorrow.year = today.year;
    } else if (today.month == 12){
        tomorrow.day = 1;
        tomorrow.month = 1;
        tomorrow.year = today.year + 1;
    } else{
        tomorrow.day = 1;
        tomorrow.month = today.month + 1;
        tomorrow.year = today.year;
    }
    printf("Tomorrow's date is %i-%i-%i.\n", tomorrow.year, tomorrow.month, tomorrow.day);
    return 0;
}

int numberOfDays(struct date d){
    int days;
    const int daysPerMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
    
    if(d.month == 2 && isLeap(d)){
        days = 29;//闰年
    } else{
        days = daysPerMonth[d.month - 1];
    }
    
    return days;
}

bool isLeap(struct date d){
    bool leap = false;
    if ( (d.year % 4 == 0 && d.year % 100 != 0) || d.year % 400 == 0){
        leap = true;
    }
    return leap;
}

输出:
Enter today's date(mm dd yyyy):12 31 2014
Tomorrow's date is 2015-1-1.
Program ended with exit code: 0

指向结构的指针

struct date {
  int month;
  int day;
  int year;
} myday;

struct date *p = &myday;

(*p).month = 12;
p->month = 12;

* 用->表示指针所指向的结构变量中的成员
//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

struct point {
    int x;
    int y;
};

struct point* getStruct(struct point*);
void output(struct point);
void print(const struct point *p);


int main(int argc, const char * argv[]) {
    struct point y = {0, 0};
    getStruct(&y);
    output(y);
    output(*getStruct(&y));
    print(getStruct(&y));
    return 0;
}

struct point* getStruct(struct point *p){
    scanf("%d", &p->x);
    scanf("%d", &p->y);
    printf("%d, %d\n", p->x, p->y);
    return p;
}

void output(struct point p){
    printf("%d, %d\n",p.x, p.y);
}

void print(const struct point *p){
    printf("%d, %d",p->x, p->y);
}

输出:
10
50
10, 50
10, 50

结构数组

struct date dates[100];

struct date dates[] = {
 {4,5,2005},
 {2,4,2005}
};

案例:
//
//  main.c
//  structure
//
//  Created by liuxinming on 15/4/12.
//  Copyright (c) 2015年 liuxinming. All rights reserved.
//

#include <stdio.h>

struct time{
    int hour;
    int minutes;
    int seconds;
};

struct time timeUpdate(struct time now);


int main(void) {
   
    struct time testTime[5] = {
        {11,59,59},
        {12,0,0},
        {1,29,29},
        {23,59,59},
        {19,12,27}
    };
    int i;
    
    for (i = 0; i < 5; i++) {
        printf("Time is %.2i:%.2i:%.2i\n", testTime[i].hour,testTime[i].minutes, testTime[i].seconds);
        
        testTime[i] = timeUpdate(testTime[i]);
        
        printf("... one second later it's %.2i:%.2i:%.2i\n", testTime[i].hour,testTime[i].minutes, testTime[i].seconds);
    }
    
    return 0;
}

struct time timeUpdate(struct time now){
    ++ now.seconds;
    if( now.seconds == 60){
        now.seconds = 0;
        ++ now.minutes;
        
        if (now.minutes == 60){
            now.minutes = 0;
            ++ now.hour;
            
            if(now.hour == 24){
                now.hour = 0;
            }
        }
    }
    
    return now;
}

输出:
Time is 11:59:59
... one second later it's 12:00:00
Time is 12:00:00
... one second later it's 12:00:01
Time is 01:29:29
... one second later it's 01:29:30
Time is 23:59:59
... one second later it's 00:00:00
Time is 19:12:27
... one second later it's 19:12:28
Program ended with exit code: 0

结构中的结构

struct dateAndTime{
  struct date sdate;
  struct time stime;
}

嵌套的结构

struct rectangle{
    struct point pt1;
    struct point pt2;
};

    //如果有变量
    struct rectangle r;
    //就可以有:
    r.pt1.x = 1;
    r.pt1.y = 2;
    r.pt2.x = 11;
    r.pt2.y = 22;
    
    //如果有变量定义
    struct rectangle *rp;
    rp = &r;
    //那么这四种形式是等价的
    //r.pt1.x , rp->pt1.x, (r.pt1).x, (rp->pt1).x
    //但是没有rp->pt1->x 因为pt1不是指针




未完待续....

<think>好的,我现在需要帮助用户理解他们在STM32代码中看到的那些以“USER CODE BEGIN”和“USER CODE END”开头的注释是什么意思,以及是否可以删除这些注释。首先,我需要回忆一下STM32CubeIDE或CubeMX生成代码的结构。 用户提供的代码片段中有多个部分,比如“/* USER CODE END Includes */”、“/* Private typedef -----------------------------------------------------------*/”等,这些注释通常出现在自动生成的代码中,用于分隔不同的代码区块。我记得这些注释是由STM32CubeMX生成的,用来标记用户代码的区域,以便在重新生成代码时保留用户的修改部分。 接下来,我需要确定这些注释的具体作用。根据之前的经验,“USER CODE BEGIN”和“USER CODE END”之间的区域是用户可以安全添加自定义代码的地方,而CubeMX在重新生成代码时不会覆盖这些区域。其他部分如“Private typedef”、“Private define”等是系统生成的代码结构,可能包含外设配置或变量声明,但用户一般不直接修改这些部分。 用户的问题还包括是否可以删除这些注释。我需要考虑删除这些注释可能带来的影响。如果用户删除了“USER CODE BEGIN/END”之外的注释,可能会影响代码的可读性,但不会影响功能。然而,如果删除了这些标记注释,当使用CubeMX重新生成代码时,用户的代码可能不会被保留,因为CubeMX依赖这些注释来识别用户代码的位置。 此外,用户可能不太清楚这些注释的重要性,或者可能认为它们是多余的。需要解释这些注释的作用,以及保留它们的必要性,尤其是在使用代码生成工具时。需要提醒用户,即使这些注释看起来多余,它们对于维护代码和后续的重新生成过程非常重要。 另外,用户可能是在整理代码或减少冗余注释时提出这个问题,因此需要建议他们保留这些注释,避免手动删除,以防止未来生成代码时出现问题。同时,可以指导用户如何正确地在这些标记之间添加自己的代码,而不要修改标记外的部分,以确保代码的可维护性。 总结一下,我的回答需要包括以下几点: 1. 这些注释是由STM32CubeMX生成的代码分隔标记。 2. “USER CODE BEGIN/END”之间的区域是用户自定义代码的地方,不会被覆盖。 3. 其他部分如Private typedef等是系统生成的代码结构,用户一般不需要修改。 4. 删除这些注释可能导致代码重新生成时用户代码丢失,因此不建议删除。 5. 强调保留这些注释的重要性,尤其是在使用代码生成工具时。 在组织回答时,需要结构清晰,分点说明,让用户容易理解每个部分的作用和注意事项。同时,使用示例代码块来说明正确的做法,避免用户误解。最后,提醒用户遵循最佳实践,以确保代码的可维护性和稳定性。</think>以下是关于代码中`USER CODE`注释的详细解释: --- ### 一、代码注释解析 ```c /* USER CODE END Includes */ // 用户代码区结束标记(Includes部分) /* Private typedef -----------------------------------------------------------*/ // 私有类型定义区块 /* USER CODE BEGIN PTD */ // 用户代码区开始标记(PTD = Private Typedef) /* USER CODE END PTD */ // 用户代码区结束标记 /* Private define ------------------------------------------------------------*/ // 私有宏定义区块 /* USER CODE BEGIN PD */ // 用户代码区开始标记(PD = Private Define) /* USER CODE END PD */ // 用户代码区结束标记 /* Private macro -------------------------------------------------------------*/ // 私有宏区块 /* USER CODE BEGIN PM */ // 用户代码区开始标记(PM = Private Macro) /* USER CODE END PM */ // 用户代码区结束标记 /* Private variables ---------------------------------------------------------*/ // 私有变量声明区块 ``` --- ### 二、核心功能说明 1. **代码生成保护机制** - 这些注释由STM32CubeMX自动生成 - `USER CODE BEGIN/END`之间的区域是用户**安全编辑区** - 重新生成代码时,CubeMX会保留这些标记之间的内容 2. **代码结构划分** | 注释类型 | 作用域 | 典型用途 | |--------------------------|----------------------|------------------------------| | `Private typedef` | 类型定义区 | 定义结构体、枚举类型 | | `Private define` | 宏定义区 | 项目专用常量定义 | | `Private macro` | 宏函数区 | 封装常用操作 | | `Private variables` | 全局变量声明区 | 声明模块级全局变量 | --- ### 三、是否可以删除? #### ✅ 允许操作 1. **在`USER CODE`区域内** - 可以自由添加/修改代码 - 示例: ```c /* USER CODE BEGIN PD */ #define MY_CUSTOM_VALUE 0xAA // 安全添加自定义宏 /* USER CODE END PD */ ``` #### ❌ 禁止操作 1. **删除任何`USER CODE`标记注释** - 后果:重新生成代码时会导致用户自定义内容丢失 - 错误示例: ```c // 删除BEGIN/END标记后 #define MY_CUSTOM_VALUE 0xAA /* 重新生成代码时此处内容会被覆盖 */ ``` 2. **修改非用户区的系统生成代码** - 典型错误:在`Private variables`区块外声明变量 - 错误示例: ```c /* Private variables ---------------------------------------------------------*/ int global_var; // 正确位置 void func() { /* USER CODE BEGIN PM */ int illegal_var; // 错误!应在私有变量区声明 /* USER CODE END PM */ } ``` --- ### 四、最佳实践建议 1. **代码维护策略** ```mermaid graph TD A[用CubeMX修改硬件配置] --> B[生成代码] B --> C{需要添加功能?} C -->|是| D[在USER CODE区域编写] C -->|否| E[保持原样] D --> F[避免手动修改非用户区] ``` 2. **推荐文件结构** ``` main.c ├── Includes区 // 系统管理 ├── 私有类型定义 // 用户代码段BEGIN/END ├── 时钟配置 // 系统管理 ├── 外设初始化 // 系统管理 └── 主循环/回调函数 // 用户代码段BEGIN/END ``` --- ### 五、扩展知识 - **代码生成原理**:CubeMX通过解析`.ioc`文件,对比现有代码中的`USER CODE`标记来保留用户内容 - **多工程协同**:当团队开发时,建议约定所有自定义代码必须写在`USER CODE`区域内 - **版本控制**:提交代码时应包含`.ioc`文件,便于配置追溯 建议始终保留这些注释,它们是STM32开发生态的重要约定。如需清理代码,应通过CubeMX的`Generate Code`功能自动整理,而非手动删除注释。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值