链接: B站Up

C程序基本语法

1.C 程序的基本结构

#include <stdio.h>  // 头文件(输入输出库)

int app_main() {        // 主函数,程序入口
    printf("Hello, World!\n");  // 打印语句
    return 0;       // 返回状态码(0表示成功)
}

2.变量与数据类型

类型 示例 说明
int int a = 10; 整型(4字节)
float float b = 3.14; 单精度浮点型(4字节)
double double c = 3.14159; 双精度浮点型(8字节)
char char d = 'A'; 字符型(1字节)
bool bool f = true; 布尔类型,不是真就是假只有两个值

变量声明与赋值

int age = 20;          // 声明并赋值
float price;
price = 99.8;          // 先声明后赋值

常量

const int DAYS = 7;    // 不可修改的常量
#define PI 3.14159     // 宏定义(无分号)

3.运算符

在这里插入图片描述

4.控制流

条件语句

// if-else
if (score >= 60) {
    printf("Pass!\n");
} else {
    printf("Fail!\n");
}

// switch-case
switch (grade) {
    case 'A': printf("Excellent!"); break;
    case 'B': printf("Good!"); break;
    default: printf("Invalid grade.");
}

循环语句

// for 循环
for (int i = 0; i < 5; i++) {
    printf("%d ", i);  // 输出 0 1 2 3 4
}

// while 循环
int count = 0;
while (count < 3) {
    printf("Count: %d\n", count);
    count++;
}

5.数组

int numbers[5] = {1, 2, 3, 4, 5};  // 声明并初始化
printf("%d", numbers[0]);          // 访问第一个元素(下标从0开始)

// 遍历数组
for (int i = 0; i < 5; i++) {
    printf("%d ", numbers[i]);
}

6.函数

// 函数定义
int add(int a, int b) {
    return a + b;
}

// 函数调用
int result = add(3, 5);
printf("Sum: %d", result);

7.指针(基础概念)

int var = 10;
int *ptr = &var;      // ptr指向var的地址
printf("Value: %d\n", *ptr);  // 通过指针访问值(输出10)

用途:
动态内存分配(如 malloc)。
函数参数传递(修改实参的值)。

8.结构体(自定义类型)

typedef struct {
    int age;
    char name[20];
}People_T;
People_T peopleT = {.age = 18, .name = "zhangsan"};

void app_main(void)
{ 
    peopleT.age = 20;
    printf("peopleT.age = %d\n", peopleT.age);
    
}

C++基本语法

1.C++程序结构

#include <iostream>  // 输入输出流头文件 

int num=10;

int main() {         // 主函数
    std::cout << "我有" << num << "个苹果" << std::endl; // 输出
    return 0;
}

2.变量与数据类型

基本类型(扩展自 C):string 字符串类型
示例:string s = “C++”;

类型推断(C++11 新增功能)
auto x = 10; // 自动推断为 int
auto y = 3.14; // 自动推断为 double

3.运算符(新增)

运算符 用途 示例
:: 作用域解析 std::cout
new 动态内存管理 int* p = new int;
delete 动态内存管理
<< 流操作符 cout << x;
>> 流操作符

4.控制流(与 C 相同)

条件语句: if-else, switch-case
循环语句: for、while, do-while
范围 for 循环(C++11):

int arr[] = {1, 2, 3};
for (int num : arr) {  // 遍历数组
    cout << num << " ";
}

C++核心特性

1.函数增强

函数重载(Overloading)

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; } // 同名函数,参数不同

规则:函数名相同,参数类型或数量不同。

2.面向对象(OOD)

类与对象

class People {          // 类定义
private:
    string name;         // 私有成员
    int age;
public:
    void setName(string n) { name = n; } // 公有方法
    string getName() { return name; }
    void setAge(int a) 
    { 
        if(a<0){
            return;        
        }
        age = a; 
    } // 公有方法
    string getAge() { return age; }
};

People people = People();              // 创建对象
people.setName("Alice");
people.setAge(-1);//不会生效
cout << people.getName();    // 输出 "Alice"

这段代码是 C++ 面向对象编程(OOP)的基础示例,核心展示了 “类(Class)” 与 “对象(Object)” 的定义和使用,以及 OOP 核心特性 ——封装的实现方式。代码通过定义People类抽象出 “人” 的属性(姓名、年龄)和行为(设置 / 获取属性),并通过访问权限控制保护数据安全,最终创建类的实例(对象)完成属性的操作与校验。

构造函数和析构函数

class Box {
public:
    Box() { cout << "对象创建了"; }  // 对象创建时自动调用,可以放些初始化函数
    ~Box() { cout << "对象销毁了"; }  // 对象销毁时自动调用,可以释放资源
};

构造函数(Box()):
对象创建时自动执行,专门用来做初始化(比如给成员变量赋值、申请内存),这段代码里只是打印 “对象创建了”。
析构函数(~Box()):
对象销毁时自动执行,专门用来做清理(比如释放内存、关闭文件),这段代码里只是打印 “对象销毁了”。

3.动态内存管理

int* p = new int(10);  // 动态分配内存
delete p;              // 释放内存

// 动态数组
int* arr = new int[5]{1, 2, 3};
delete[] arr;

对比 C:new/delete 替代 malloc/free,会调用构造 / 析构函数。

4.常用容器

#include <vector>
#include <map>

vector<int> v = {1, 2, 3};  // 动态数组
v.push_back(4);             // 添加元素

map<string, int> m;         // 键值对
m["Alice"] = 90;

这是 C++ 里常用容器的基础示例,展示了两个最常用的标准容器:
vector是 “可以自动扩容的数组”,替代 C 语言里的普通数组;
map是 “键值对字典”,可以通过 “键” 快速找到对应的 “值”。

5.智能指针(C++11)

#include <memory>
unique_ptr<int> p1(new int(10)); // 自动释放内存
shared_ptr<int> p2 = make_shared<int>(20);

这是 C++11 新增的智能指针(用来自动管理动态内存的工具),核心是解决普通指针容易忘释放内存导致的 “内存泄漏” 问题,示例里是两种常用智能指针:

  1. 先明确前提
    普通指针用new申请内存后,得手动delete释放(否则内存泄漏);而智能指针会在不需要时自动释放内存,不用手动管。
  2. 代码里的两种智能指针
    #include :使用智能指针必须包含的头文件;
    (1)unique_ptr(独占型智能指针)
    代码:unique_ptr p1(new int(10));
    特点:unique_ptr:一人独享,用完就自动还(内存),不让别人碰;
    (2)shared_ptr(共享型智能指针)
    代码:shared_ptr p2 = make_shared(20);
    特点:shared_ptr:多人共用,记着有多少人在用,最后一个人用完才自动还(内存);

6.C VS C++关键区别

特性 C C++
输入输出 printf
scanf
cout
cin
字符串 char[] string类
内存管理 malloc
free
new
delete
面向对象 不支持 类、继承、多态
函数 无重载 支持重载和默认参数

混合编程C&C++

C 和 C++ 的混合编程在实际开发中非常常见,尤其是在嵌入式系统、硬件驱动开发或复用现有 C 库时

1、C++ 中引用 C 标准库函数

#include <cstdio>  // C++ 版本的 C 标准库头文件
#include <cmath>

int main() {
    std::printf("Hello from C!\n");  // 需加 std::
    double x = std::sqrt(2.0);      // 明确使用 std 命名空间
    return 0;
}

C++ 把 C 的标准库头文件(比如 C 的<stdio.h>)改成了去掉.h、加c前缀的形式(比如),并且把这些 C 函数放进了std命名空间里。
所以在 C++ 里用 C 的函数(比如printf、sqrt),得在前面加std::
(比如std::printf)。

2. 头文件的兼容性

目标:让同一头文件既能被 C 编译器也能被 C++ 编译器正确解析。
方法:在 C 头文件中添加 __cplusplus 判断。

#ifdef __cplusplus  // 如果是 C++ 编译器
extern "C" {        // 按 C 方式导出符号
#endif

// C 函数声明
void c_function(int x);

#ifdef __cplusplus
}
#endif

前后两段#ifdef __cplusplus是成对、连在一起的,本质是 “给中间的函数声明套了一个「C++ 编译器专属的外壳」”

3. C++ 引入 C 写的函数

#include <iostream>  // 普通C++头文件,正常引入(和调用C函数无关)

extern "C" {         // 关键:开启“C语言规则模式”
    #include "my_lib.h"  // 引入C头文件 → 里面的所有函数(比如c_function)都按C规则处理
}                    // 关闭“C语言规则模式”

int main() {
    c_function(42);  // 调用C函数 → 因为上面套了extern "C",C++能正确找到这个C函数
    return 0;
}

如果不这么写。。。

#include "my_lib.h"  // 没套extern "C"
int main() {
    c_function(42);  // 编译/链接报错!
    return 0;
}

原因:C++ 编译器会给c_function改名字,而 C 语言写的c_function还是原名字,两者对不上,就会提示 “找不到 c_function 函数”。

4. C 调用 C++ 函数

C++代码

#include <iostream>
extern "C" {  // 强制以 C 方式导出函数
    void cpp_function(int x) {
        std::cout << "C++ function called with: " << x << std::endl;
    }
}

C代码

#include <stdio.h>
extern void cpp_function(int);  // 声明 C++ 函数

int main() {
    cpp_function(42);  // 调用 C++ 函数
    return 0;
}

C++ 端:给要被调用的函数套extern “C” { … },强制按 C 规则编译(保留原函数名);
C 端:用extern声明这个 C++ 函数(告诉 C 编译器 “有这个函数”);
编译链接:分别编译 C/C++ 代码,再链接成可执行文件,C 代码就能直接调用。

PS:
✅ C++ 默认行为:编译函数时会 “篡改” 函数名(专业叫「名字修饰 / Name Mangling」),比如cpp_function(int)会被改成_Z11cpp_functioni这种格式;
✅ C 的特性:C 编译器不会改函数名,只会用原名字(比如cpp_function).

C++ 改函数名的核心原因:为了支持「函数重载」
C++ 自己为能链接到
只有和 C 交互时才出问题

5.总结

在这里插入图片描述

更改点灯程序为C++程序

1.更改文件名

在这里插入图片描述

2.更改CMakeList.txt文件

在这里插入图片描述

3、添加 extern “C” 修饰 app_main 函数

因为 app_main 函数比较特殊,是系统自动会调用这个函数名称,而 C++ 编译器会将函数名重新修饰,这会导致系统找不到这个 app_main 函数名,加了 extern “C” 告诉编译器这个函数安装 C 的标准走不要对他进行函数名修饰
在这里插入图片描述

#include <cstdio>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"

extern "C" void app_main(void)
{
    std::printf("Hello World!\n");
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = (1ULL << GPIO_NUM_10);
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_config(&io_conf);

    while (1)
    {
        gpio_set_level(GPIO_NUM_10, 0);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_NUM_10, 1);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
#include <stdio.h> 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

void app_main(void)
{
    printf("Hello World!\n");
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = (1ULL<<GPIO_NUM_10);
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_config(&io_conf);

    while (1)
    {
        gpio_set_level(GPIO_NUM_10, 0);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        gpio_set_level(GPIO_NUM_10, 1);
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

4. C版本与C++版本代码核心差异说明

  1. app_main函数声明差异

    • C版本:void app_main(void)
    • C++版本:extern "C" void app_main(void)
    • 作用/原因:C++ 编译器会修改函数名,加extern "C"强制按 C 规则保留app_main原名,保证系统能找到入口函数
  2. printf调用方式差异

    • C版本:printf("Hello World!\n");
    • C++版本:std::printf("Hello World!\n");
    • 作用/原因:C++ 将 C 标准库函数归入std命名空间,必须加std::才能调用(或加using namespace std;
  3. 头文件(隐含差异)

    • C版本:#include <stdio.h>(C 标准头文件)
    • C++版本:#include <cstdio>(截图里能看到)
    • 作用/原因:C++ 推荐用cXXX格式的头文件(如<cstdio>)替代 C 的XXX.h(如<stdio.h>
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐