【C语言】关于C11的一些新特性
相比于VC++ 6.0使用的ANSI C标准,VS2022使用的C11标准与上一代有很多不同,相比之前的 C 标准(如 C89/C90 和 C99),引入了一些新的功能、特性和改进。以下是 C11 标准相对于之前版本的一些主要变化和新增内容:
1.多线程支持:
在 C11 标准中引入了 <threads.h> 头文件,其中定义了一组函数和类型,用于支持线程相关的操作。这个头文件提供了一些函数和类型,可以用于创建、管理和同步线程。
以下是 <threads.h> 中常见的一些函数和类型:
-
类型定义:
thrd_t:代表线程的类型。mtx_t:代表互斥锁的类型。cnd_t:代表条件变量的类型。
-
线程函数:
thrd_create:创建一个新的线程。thrd_exit:终止当前线程。thrd_join:等待指定线程终止。thrd_detach:设置线程为分离状态,使其在终止后自动释放资源。
-
互斥锁函数:
mtx_init:初始化互斥锁。mtx_lock:锁定互斥锁。mtx_unlock:解锁互斥锁。mtx_destroy:销毁互斥锁。
-
条件变量函数:
cnd_init:初始化条件变量。cnd_signal:发送信号给等待条件变量的线程。cnd_broadcast:广播信号给所有等待条件变量的线程。cnd_wait:等待条件变量变为真。
以下是一个示例用法:
#include <stdio.h>
#include <threads.h>mtx_t mutex; // 互斥锁int shared_data = 0; // 共享的数据int increment_data(void* arg) {mtx_lock(&mutex); // 锁定互斥锁shared_data++; // 修改共享数据mtx_unlock(&mutex); // 解锁互斥锁return 0;
}int main() {thrd_t thread;mtx_init(&mutex, mtx_plain); // 初始化互斥锁// 创建线程if (thrd_create(&thread, increment_data, NULL) != thrd_success) {fprintf(stderr, "无法创建线程\n");return 1;}// 等待线程终止if (thrd_join(thread, NULL) != thrd_success) {fprintf(stderr, "无法等待线程\n");return 1;}printf("共享数据的值: %d\n", shared_data);mtx_destroy(&mutex); // 销毁互斥锁return 0;
}
2.泛型选择表达式:
_Generic 关键字是 C11 标准引入的一个新特性,用于根据表达式的类型选择不同的代码块。它主要用于实现泛型编程中的条件选择,允许编写更通用的代码,根据表达式的类型动态地选择不同的处理方式。
_Generic 关键字的基本语法形式如下:
_Generic(expression,type1: code_block1,type2: code_block2,//...default: default_code_block
)
其中:
expression是要进行类型选择的表达式。type1,type2, ... 是不同的类型。code_block1,code_block2, ... 是与对应类型匹配的代码块。default是可选的默认代码块。
下举一个简单的例子:
#include <stdio.h>#define PrintValue(x) _Generic((x), \int: printf("整数: %d\n", x), \float: printf("浮点数: %f\n", x), \double: printf("双精度浮点数: %lf\n", x), \default: printf("其他类型\n") \
)int main() {int a = 10;float b = 3.14f;double c = 2.71828;PrintValue(a); // 整数: 10PrintValue(b); // 浮点数: 3.140000PrintValue(c); // 双精度浮点数: 2.718280char d = 'A';PrintValue(d); // 其他类型return 0;
}
在这个例子中,_Generic 根据传入参数的不同类型,选择不同的 printf 语句进行输出。如果传入的参数类型不在指定的类型范围内,则使用默认的输出方式。这样,可以根据表达式的类型,动态地选择不同的代码执行路径。
使用 _Generic 关键字可以编写更灵活和通用的代码,使得代码在编译期间就能进行类型检查和类型选择,提高了代码的可读性和通用性。
3.匿名结构体和联合体:
在 C11 标准中引入了匿名结构体和匿名联合体的概念,允许在不提供名称的情况下定义结构体和联合体,使其更为灵活。
匿名结构体
匿名结构体允许您定义一个没有标签名称的结构体。这种结构体可以直接在声明变量时定义,而无需指定结构体名称。它在某些情况下能够简化代码。
#include <stdio.h>int main() {struct { // 匿名结构体int x;int y;} point; // 定义匿名结构体变量point.x = 10;point.y = 20;printf("x 坐标: %d, y 坐标: %d\n", point.x, point.y);return 0;
}
匿名联合体
匿名联合体与匿名结构体类似,允许定义没有标签名称的联合体。这种联合体也可以直接在声明变量时定义,而无需指定联合体名称。
#include <stdio.h>int main() {union { // 匿名联合体int intValue;float floatValue;} data; // 定义匿名联合体变量data.intValue = 42;printf("整数值: %d\n", data.intValue);data.floatValue = 3.14f;printf("浮点数值: %f\n", data.floatValue);return 0;
}
使用匿名结构体和匿名联合体时要注意,由于它们没有名称,因此无法在其他地方使用相同的定义。因此,这种方式适用于某些情况下仅需在局部范围内使用的结构体或联合体。
4.静态断言:
_Static_assert 是 C11 标准引入的一个关键字,用于在编译时执行静态断言(static assertion)。静态断言是指在编译时检查条件是否为真,如果条件为假则会触发编译器错误,防止程序继续编译。
_Static_assert(constant_expression, "error_message");
constant_expression 是在编译时期计算结果为常量的表达式。如果该表达式的值为 0(假),则会触发静态断言,编译器会显示指定的错误信息。
error_message 是一个字符串常量,表示在触发断言时显示的错误信息。
#include <stdio.h>#define ARRAY_SIZE 10_Static_assert(ARRAY_SIZE > 5, "数组大小必须大于 5");int main() {printf("程序正常运行\n");return 0;
}
在上面的例子中,如果 ARRAY_SIZE 小于或等于 5,编译将会失败并显示 "数组大小必须大于 5" 的错误信息。这样的静态断言可用于在编译时期检查常量表达式的值,确保代码的正确性。
静态断言的使用可以在编译阶段发现潜在的错误,提高代码质量,并在一定程度上增强代码的可读性。通常用于检查各种常量表达式是否符合预期,并提前发现错误,避免将错误带入到运行时。
5.可重入的标准库函数:
C11 引入了一些可重入的标准库函数,这些函数可以在多线程环境下安全地被多个线程同时调用,而不会导致竞态条件或数据损坏。
可重入函数具有以下特点:
- 不会使用静态数据。
- 不会修改除了传入参数和返回结果以外的任何数据。
- 在多线程环境下可以安全地并发调用。
以下是一些 C11 标准中引入的可重入函数示例:
-
rand_r:生成伪随机数的函数,传入一个状态变量,返回下一个伪随机数。通过传递不同的状态变量,可以在多线程环境下安全地使用这个函数。 -
gmtime_r和localtime_r:这两个函数用于将时间表示为日历时间,分别用于将时间戳转换为 UTC 时间和本地时间。这些函数的可重入版本使用了用户提供的结构体指针作为输出参数,而不是使用静态缓冲区。 -
asctime_r、ctime_r、strtok_r:这些函数是asctime、ctime和strtok的可重入版本。它们接收用户提供的缓冲区或状态指针,而不使用静态数据。 -
getenv和putenv:这两个函数是用于环境变量的操作,getenv_r是getenv的可重入版本,接收用户提供的缓冲区来存储环境变量的值。
这些可重入的标准库函数为多线程编程提供了更安全和可靠的基础,因为它们避免了使用静态数据,而是使用用户提供的参数来存储结果或中间状态。这样可以确保这些函数在多线程环境中能够安全地被调用,而不会产生竞态条件或数据损坏。
6.原子操作:
C11 标准引入了原子操作,提供了一组函数和类型,用于支持多线程并发访问共享变量时的原子性操作。原子操作是在不被中断的情况下执行的操作,保证了对共享变量的操作不会被其他线程的操作所干扰。
C11 中原子操作的函数位于 <stdatomic.h> 头文件中,并定义了一些原子类型和原子操作函数。以下是一些常见的原子操作函数和类型:
-
原子类型:
atomic_bool,atomic_char,atomic_int,atomic_long,atomic_llong,atomic_short,atomic_float,atomic_double,atomic_ptr等,这些类型用于创建对应类型的原子变量。
-
原子加载和存储操作:
atomic_load:从原子变量中加载值。atomic_store:将值存储到原子变量。atomic_exchange:交换原子变量的值,并返回原来的值。
-
原子递增和递减操作:
atomic_fetch_add:将指定值加到原子变量上。atomic_fetch_sub:将指定值从原子变量中减去。
-
原子比较和交换操作(CAS):
atomic_compare_exchange_strong:如果原子变量的值等于给定的旧值,则用新值替换它。atomic_compare_exchange_weak:类似于atomic_compare_exchange_strong,但在某些情况下会使用弱型别的 CAS。
#include <stdio.h>
#include <stdatomic.h>
#include <threads.h>atomic_int counter = ATOMIC_VAR_INIT(0); // 初始化原子变量int increment_counter(void* arg) {for (int i = 0; i < 10000; ++i) {atomic_fetch_add(&counter, 1); // 原子递增操作}return 0;
}int main() {thrd_t thread1, thread2;thrd_create(&thread1, increment_counter, NULL);thrd_create(&thread2, increment_counter, NULL);thrd_join(thread1, NULL);thrd_join(thread2, NULL);printf("Counter: %d\n", atomic_load(&counter)); // 输出原子变量的值return 0;
}
这个示例演示了如何使用 C11 的原子操作来安全地递增一个共享的原子变量 counter。原子操作确保了对共享变量的递增操作不会被其他线程的操作所干扰,避免了竞态条件。原子操作函数提供了一种安全而有效的方式来处理并发编程中的共享资源。
7.内存模型:
C11 引入了对 C 语言的内存模型的显式支持,定义了一些规则和保证,以便程序员更好地理解并发程序中的内存访问和同步。C11 内存模型描述了程序中各种内存访问操作的行为和规则。
C11 中的内存模型包含以下重要概念:
1.顺序一致性(Sequential Consistency):
C11 内存模型默认情况下提供了顺序一致性的保证。这意味着程序中的所有线程看到的内存操作都好像是按照一个全局的、全局顺序的序列来执行的。这种模型简化了多线程编程中对内存操作的理解。
2.原子类型和原子操作:
C11 引入了原子类型(例如 atomic_int 等)和原子操作函数(例如 atomic_load、atomic_store 等),用于执行原子性操作,保证在多线程环境中对共享变量的操作是原子的。
3.内存顺序(Memory Orderings):
C11 提供了对内存操作的顺序控制,即通过指定适当的 memory order 来控制原子操作的顺序。比如 memory_order_relaxed、memory_order_acquire、memory_order_release 等。
4.原子性操作的同步语义:
使用原子操作函数可以实现一些同步语义,比如 release-acquire、acquire-release 和 sequentially-consistent。
5.内存屏障(Memory Barriers):
内存屏障是一种指令,用于强制内存操作的顺序和同步。C11 中使用 atomic_thread_fence 函数来实现内存屏障,它可以确保在其前后的内存操作的执行顺序。
C11 内存模型提供了一种明确定义多线程程序中对共享内存访问的行为方式,有助于程序员更好地理解和控制多线程程序中的内存访问。这对于编写并发程序,避免竞态条件(Race Conditions)、数据竞争(Data Races)以及其他并发问题是非常重要的。
8.Unicode支持改进:
C11 标准增强了对 Unicode 字符集的支持,以更好地处理和操作 Unicode 字符串和字符。这些改进包括一些新的数据类型、宏以及支持 Unicode 的字符串处理函数。
以下是 C11 中 Unicode 支持的一些改进:
1.char16_t 和 char32_t 类型:
引入了 char16_t 和 char32_t 类型,用于分别表示 UTF-16 和 UTF-32 编码的 Unicode 字符。这些类型提供了直接处理不同宽度的 Unicode 字符的机制。
2.u 前缀和 U 前缀:
C11 标准引入了 u 前缀表示 UTF-16 编码的字符串字面量,以及 U 前缀表示 UTF-32 编码的字符串字面量。例如,u"Hello" 表示一个 UTF-16 编码的字符串。
3.char16_t 和 char32_t 字符串处理函数:
C11 引入了一些新的 Unicode 字符串处理函数,如 u16len、u32len、u16tou32、u32tou16 等,用于处理 char16_t 和 char32_t 类型的 Unicode 字符串。
4.<uchar.h> 头文件:
C11 引入了 <uchar.h> 头文件,其中包含了用于 Unicode 字符处理的新函数和宏,例如 c16rtomb、c32rtomb、mbrtoc16、mbrtoc32 等函数。
这些改进使得 C11 更好地支持 Unicode 字符串和字符的处理,提供了更直接、更全面的机制来处理不同宽度的 Unicode 编码。这些改进有助于编写更具有国际化和多语言支持的程序,使得处理 Unicode 字符集更加方便和灵活。
9.新增的库函数:
引入了一些新的标准库函数,如 aligned_alloc、fmax, fmin 等,用于提供更多的数学和内存管理功能。
C11 标准引入了一些新的库函数,以增强 C 语言的功能性和标准库的支持。这些新函数提供了更多的功能,以适应新的需求和编程模式。以下是一些 C11 新增的库函数:
宽字符字符串处理函数:
wchar_t 类型的字符串处理函数:wcsncpy_s、wcsncat_s、wcsnlen 等函数,用于宽字符字符串的拷贝、连接和长度计算。
安全性增强函数:
安全性增强函数:例如 strcpy_s、strncpy_s、strcat_s、strtok_s 等函数,用于字符串操作,可以避免缓冲区溢出问题。
快速数学运算函数:
快速数学运算函数:例如 sin, cos, tan, exp, log, sqrt 等数学函数的 _FMA、_FMAF、_FMAL 版本,用于提高数学运算的性能。
aligned_alloc()
aligned_alloc 是 C11 引入的函数,用于分配内存并保证返回的内存地址满足特定的对齐要求。它的函数原型如下:
void *aligned_alloc(size_t alignment, size_t size);
alignment 参数是所需对齐的字节数,必须是 2 的幂且至少为 sizeof(void *) 的倍数。
size 参数是要分配的内存大小,以字节为单位。
aligned_alloc 函数会返回一个指向对齐内存块的指针。该函数可以用于需要特定内存对齐要求的情况,比如 SSE、AVX 等特定指令集的数据要求特定对齐方式的情况。
fmax(), fmin()
fmax() 和 fmin() 是 C11 新增的数学函数,用于返回两个浮点数的最大值和最小值。fmax 返回两个参数中的最大值,fmin 返回两个参数中的最小值。
double fmax(double x, double y);
float fmaxf(float x, float y);
long double fmaxl(long double x, long double y);
这些新增的函数增强了 C 语言标准库的功能性和安全性,提供了更多的工具和功能,使得编程更为方便、高效和安全。这些函数能够更好地支持并发编程、Unicode 字符串处理、泛型编程和数学运算等方面。
相关文章:
【C语言】关于C11的一些新特性
相比于VC 6.0使用的ANSI C标准,VS2022使用的C11标准与上一代有很多不同,相比之前的 C 标准(如 C89/C90 和 C99),引入了一些新的功能、特性和改进。以下是 C11 标准相对于之前版本的一些主要变化和新增内容:…...
牛的速记(c++题解)
题目描述 奶牛们误解了速记的含义。他们是这样理解的: 给出一个少于255个字母的小写字母串。 找到一个出现次数最多的字母,将该字母从字母串中统统删去,如果出现次数最多的字母不止一个,就删去在字母表中靠前的一个,即…...
使用ffmpeg+flv.js + websokect播放rtsp格式视频流
对于rtsp的视频流网上有很多种的解决方案,但是大的趋势还是利用ffmpeg的工具进行rtsp的视频解析进行一个推流,我最终选择bilibili开源的flv.js,代码十分的简单全部都在底层封装好了。实现的方式也比较容易理解,ffmpeg进行rtsp的视…...
OAI openair3代码结构整理
openair3代码框架结构 OAI(OpenAirInterface)是一个开源的5G网络软件平台,用于研究和开发5G网络技术。OpenAir3是OAI项目中的一个子项目,专注于5G核心网络的功能实现。 一、OpenAir3的代码主要包括以下几个部分: NAS…...
Kubernets(K8S)启动和运行 01-01 Kubernetes简介
Kubernets(K8S)启动和运行 01-01 Kubernetes简介 Kubernetes is an open source orchestrator for deploying containerized applications. It was originally developed by Google, inspired by a decade of experience deploying scalable, reliable systems in containers …...
PHP特性知识点扫盲 - 下篇
概述 在实际的生产环境中遇到了实际需要解决的问题,需要把服务部署的方式梳理出来,在同一个服务器中部署多个PHP环境,架构图如下: 架构方案 在工作实践中遇到的很多问题的普遍性都是相通的,公司运行的可新项目都是版…...
HarmonyOS应用开发之DevEco Studio安装与初次使用
1、DevEco Studio介绍 DevEco Studio是基于IntelliJ IDEA Community开源版本打造,面向华为终端全场景多设备的一站式集成开发环境(IDE),为开发者提供工程模板创建、开发、编译、调试、发布等E2E的HarmonyOS应用/服务的开发工具。…...
记录第一次在GitHub上面提交Issue
第一次在GitHub上面提交Issue,记录一下。 对着源码调了好久才发现,问题并不在程序而在模型(虽然只是一个很小的问题,但是能够解决问题,并且做出了自己的一点小小贡献,还是很开心。嘻嘻,发博客记…...
【数据库设计和SQL基础语法】--用户权限管理--数据备份和恢复策略
一、引言 数据备份和恢复是数据库管理中至关重要的任务,对于确保数据安全性和业务连续性具有重大的意义。以下是一些关键的重要性方面: 防止数据丢失: 数据备份是防止因硬件故障、人为错误、恶意攻击或其他意外事件导致数据丢失的主要手段。…...
java数据结构与算法刷题-----LeetCode70. 爬楼梯
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只…...
【Unity入门】UGUI之Slider(滑动条)
目录 一、什么是Slider?二、Slider属性与功能 一、什么是Slider? Slider控件允许用户可以通过鼠标来在预先确定的范围调节数值 我们可以在Hierarchy视图右键 -> UI ->Slider来创建滑动条 通过上图可以发现Unity内置的Slider主要有3部分&#x…...
MySQL中UNION和UNION ALL的区别有哪些?
在MySQL中如何想要对两个结果集进行合并操作,可以使用UNION和UNION ALL,如果只是想要去除掉重复的记录,属于UNION ALL 即可,但是如何想要除掉没有重复行数据,就要使用Union。本文详细向大家介绍MySQL中UNION和UNION AL…...
Android kotlin build.gradle.kts配置
1. 添加 maven 仓库 1. 1. settings配置 1. 1.1. settings.gradle repositories {maven {url https://maven.aliyun.com/repository/public/}mavenCentral() }1. 1.2. settings.gradle.kts repositories {maven {setUrl("https://maven.aliyun.com/repository/public/…...
css、js、vue常考部分面试题
css css盒子水平垂直居中方法 方法一:定位 .child{height: 100px;position: absolute;//父元素相对定位top:50%;left:50%;transform: translate(-50%,-50%); } 方法二:定位 .child{width: 100px;height: 100px;position: absolute;top:50%;left:50%…...
OpenAI ChatGPT-4开发笔记2024-03:Chat之Function Calling/Function/Tool/Tool_Choice
Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了,必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…...
二叉搜索树与双向链表
解题思路一: /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;} } */ // 一定要用自己的理解真正弄出来才行,否则没有用! // 再次提醒,计算机这种工科…...
uniapp中组件库的Checkbox 复选框 的丰富使用方法
目录 #平台差异说明 #基本使用 #自定义形状 #禁用checkbox #自定义形状 #自定义颜色 #横向排列形式 #横向两端排列形式 API #Checkbox Props #CheckboxGroup Props #CheckboxGroup Event 复选框组件一般用于需要多个选择的场景,该组件功能完整ÿ…...
Spring Cloud + Vue前后端分离-第10章 基于阿里云OSS的文件上传
源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第10章 基于阿里云OSS的文件上传 前面介绍的文件上传是基于本地文件服务器的文件上传,但是自己搭文件服务器会有很多运维的问题,比如磁盘满了要扩容…...
C++ 中的耗时计算函数
#include <time.h>int clock_gettime (clockid_t clock_id, struct timespec *tp) 获取当前 clock_id 的时钟值并存储在 tp 中。 其中 tp 是一个 timespec 结构体,在 time.h 头文件中定义: #include <time.h>:struct timespec {time_t t…...
【Element】el-form和el-table嵌套实现表格编辑并提交表单校验
一、背景 页面需要用到表格采集用户数据,提交时进行表单校验;即表格中嵌套着表单,保存时进行表单校验 二、功能实现 2.1、el-form和el-table嵌套说明 ① :model"formData" 给表单绑定数据,formData是表单的数据对象 …...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
