【C++ Primer】第二章(2 ~ 6节)
变量
变量提供一个具名的、可供程序操作的存储空间。 C++
中变量和对象一般可以互换使用。
变量定义(define)
定义形式:类型说明符(type specifier) + 一个或多个变量名组成的列表。如
int sum = 0, value, units_sold = 0;
初始化(initialize):对象在创建时获得了一个特定的值。
- 初始化不是赋值!:
- 初始化 = 创建变量 + 赋予初始值
- 赋值 = 擦除对象的当前值 + 用新值代替
- 列表初始化:使用花括号
{}
,如int units_sold{0};
注意:使用列表初始化时,如果初始值存在信息丢失的风险,编译器将报错:
long double ld = 3.1415926536;
int a{ld},b{ld}; //错误:转换未执行,因为存在丢失信息的危险
int c(ld),d = ld; //正确:转换执行,丢失部分值
- 默认初始化:定义时没有指定初始值会被默认初始化;在函数体内部的内置类型变量将不会被初始化。
- 建议初始化每一个内置类型的变量。
练习2.10:
变量的声明(declaration) vs 定义(define)
- 为了支持分离式编译,
C++
将声明和定义区分开。声明使得名字为程序所知。定义负责创建与名字关联的实体。 - extern:只是说明变量定义在其他地方。
- 只声明而不定义: 在变量名前添加关键字
extern
,如extern int i;
。但如果包含了初始值,就变成了定义:extern double pi = 3.14;
变量只能被定义一次,但是可以多次声明。定义只出现在一个文件中,其他文件使用该变量时需要对其声明。
名字的作用域(namescope)
{}
- 第一次使用变量时再定义它。
- main有全局作用域。
- 嵌套的作用域
- 同时存在全局和局部变量时,已定义局部变量的作用域中可用
::reused
显式访问全局变量reused。 - 但是用到全局变量时,尽量不适用重名的局部变量。
- 同时存在全局和局部变量时,已定义局部变量的作用域中可用
练习2.11
变量命名规范
- 需体现实际意义
- 变量名用小写字母
- 自定义类名用大写字母开头:Sales_item
- 标识符由多个单词组成,中间须有明确区分:student_loan或studentLoan,不要用studentloan。
左值和右值
- 左值(l-value)可以出现在赋值语句的左边或者右边,比如变量;
个人理解:左值是具有地址属性的对象。左值可以出现在=左边与=右边。
int i = 10; //i是左值
++i; //左值,地址为i的地址
- 右值(r-value)只能出现在赋值语句的右边,比如常量。
个人理解:不是左值的对象就是右值。或者说无法操作地址的对象就叫做右值。右值只能出现在=右边。
int i2 = i + 1; // i + 1是一个临时对象,它有地址属性,但这个地址属性无法被使用,因此为右值
int i = 10;
i++; //右值,先返回一个临时变量,临时变量的地址无法被使用,可以视作没有地址属性
复合类型
一条声明语句由一个基本数据类型(base type)和紧随其后的一个声明符(declarator)列表组成;
复合类型的声明
练习2.25
说明下列变量的类型和值。
(a) int* ip, i, &r = i;
(b) int i, *ip = 0;
(c) int* ip, ip2;
解:
- (a): ip 是一个指向 int 的指针, i 是一个 int, r 是 i 的引用。
- (b): i 是 int , ip 是一个空指针。
- (c): ip 是一个指向 int 的指针, ip2 是一个 int。
引用
一般说的引用是指的左值引用
- 引用:引用是一个对象的别名,【引用类型】引用(refer to)另外一种类型。如
int &refVal = val;
。 - 引用必须初始化。
- 引用和它的初始值是绑定bind在一起的,而不是拷贝。一旦定义就不能更改绑定为其他的对象
个人理解:引用是阉割版的指针,引用不是一个对象,而是给对象起的一个别名。
引用定义时必须被初始化,并且与初始化的值绑定在一起,不像指针能够通过+或-运算符来指向其它内存地址;
练习2.15
下面的哪个定义是不合法的?为什么?
- (a) int ival = 1.01;
- (b) int &rval1 = 1.01;
- (c) int &rval2 = ival;
- (d) int &rval3;
解:
(b)和(d)不合法,(b)引用必须绑定在对象上而不是一个常量,(d)引用必须初始化。
练习2.16
考察下面的所有赋值然后回答:哪些赋值是不合法的?为什么?哪些赋值是合法的?它们执行了哪些操作?
int i = 0, &r1 = i;
double d = 0, &r2 = d;
- (a) r2 = 3.14159;
- (b) r2 = r1;
- (c) i = r2;
- (d) r1 = d;
解:
- (a): 合法。给 d 赋值为 3.14159。
- (b): 合法。会执行自动转换(int->double)。
- (c): 合法。会发生小数截取。
- (d): 合法。会发生小数截取。
指针
int *p; //指向int型对象的指针
是一种
"指向(point to)"
另外一种类型的复合类型。定义指针类型:
int *ip1;
,从右向左读有助于阅读:1.ip1
是指针;2. 一个指向int
类型的指针。指针存放某个对象的地址。
引用不是对象,没有实际地址,因此不能定义指向引用的指针。
获取对象的地址:
int i=42; int *p = &i;
。&
是取地址符。指针的类型与所指向的对象类型必须一致(均为同一类型int、double等)
指针的值的四种状态:
1.指向一个对象;
2.指向紧邻对象的下一个位置;
3.空指针;
4.无效指针。
对无效指针的操作均会引发错误,第二种和第三种虽为有效的,但理论上是不被允许的
指针访问对象:
cout << *p;
输出p指针所指对象的数据,*
是解引用符。不能把int变量直接赋给指针
空指针不指向任何对象。使用
int *p=nullptr;
来使用空指针。指针和引用的区别:引用本身并非一个对象,引用定义后就不能绑定到其他的对象了;指针并没有此限制,相当于变量一样使用。
赋值语句永远改变的是左侧的对象。
void*
指针可以存放任意对象的地址。能存,能赋值,但不能取:因无类型,仅操作内存空间,对所存对象无法访问。
其他指针类型必须要与所指对象严格匹配。
两个指针相减的类型是
ptrdiff_t
。建议:初始化所有指针。
int* p1, p2;//*是对p1的修饰,所以p2还是int型
其他指针操作
练习2.21
请解释下述定义。在这些定义中有非法的吗?如果有,为什么?
int i = 0;
- (a) double* dp = &i;
- (b) int *ip = i;
- (c) int *p = &i;
解:
- (a): 非法。不能将一个指向
double
的指针指向int
。 - (b): 非法。不能将
int
变量赋给指针。 - (c): 合法。
练习2.23
给定指针 p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。
解:
能,可以使用try catch的异常处理来分辨指针p是否指向一个合法的对象,但通过普通控制结构无法实现。
练习2.24
在下面这段代码中为什么 p 合法而 lp 非法?
int i = 42;
void *p = &i;
long *lp = &i;
解:
void *
是从C语言那里继承过来的,可以指向任何类型的对象。 而其他指针类型必须要与所指对象严格匹配。
const限定符
- 动机:希望定义一些不能被改变值的变量。
extern const
在C++中,extern const
是用来声明外部链接的常量的关键字组合。
关键字extern
用于声明一个变量或常量是在其他地方定义的,它告诉编译器该变量或常量的定义在其他文件中。这样,在当前文件中使用这个变量或常量时,编译器会在链接过程中找到它的实际定义。
关键字const
表示该变量或常量是一个不可修改的值。它告诉编译器该标识符所表示的值在程序执行期间不会改变。
通过将extern const
结合使用,我们可以声明一个外部链接的常量,该常量的定义位于其他文件中,并且在当前文件中不可修改。
例如,假设我们有两个文件:file1.cpp和file2.cpp。在file1.cpp中定义了一个常量:
// file1.cpp
extern const int MY_CONSTANT = 10;
然后,在file2.cpp中可以使用这个常量:
// file2.cpp
extern const int MY_CONSTANT;
int main() {
// 使用MY_CONSTANT
int value = MY_CONSTANT;
// ...
return 0;
}
在这个例子中,extern const int MY_CONSTANT
的声明告诉编译器,MY_CONSTANT
的定义在其他文件中。在file2.cpp中使用MY_CONSTANT
时,编译器会在链接过程中找到它的实际定义并使用该值。同时,由于使用了const
关键字,MY_CONSTANT
的值在程序执行期间是不可修改的。
初始化和const
- const对象必须初始化,且不能被改变。
- const变量默认不能被其他文件访问,非要访问,必须在指定const定义之前加extern。要想在多个文件中使用const变量共享,定义和声明都加const关键字即可。
练习2.26
const int buf; // 不合法, const 对象必须初始化
int cnt = 0; // 合法
const int sz = cnt; // 合法
++cnt; ++sz; // 不合法, const 对象不能被改变
const的引用
- reference to const(对常量的引用):指向const对象的引用,如
const int ival=1; const int &refVal = ival;
,可以读取但不能修改refVal
。也就是底层const,因为const自带顶层const
- 临时量(temporary)对象:当编译器需要一个空间来暂存表达式的求值结果时,临时创建的一个未命名的对象。
个人理解:临时量没有地址属性,也就是一个右值。但因为是常量引用,以后都不会修改temp的值,也就用不到temp的地址属性,因此这种赋值是合法的。
- 对临时量的引用是非法行为。即当上图的ri不是常量引用时,赋值非法。
个人理解:因为普通的引用需要使用到被指变量的地址属性,而临时量是一个右值,没有地址属性,因此非法。
- const引用可能引用一个并非const的对象
指针和const
- pointer to const(指向常量的指针):不能用于改变其所指对象的值, 如
const double pi = 3.14; const double *cptr = π
。 - const pointer:指针本身是常量,也就是说指针固定指向该对象,(存放在指针中的地址不变,地址所对应的那个对象值可以修改)如
int i = 0; int *const ptr = &i;
练习2.27
下面的哪些初始化是合法的?请说明原因。
解:
int i = -1, &r = 0; // 不合法, r 必须引用一个对象
int *const p2 = &i2; // 合法,常量指针
const int i = -1, &r = 0; // 合法
const int *const p3 = &i2; // 合法
const int *p1 = &i2; // 合法
const int &const r2; // 不合法, r2 是引用, 引用自带顶层 const, 第二个const写法多余但合法, 但引用需要初始化.
const int i2 = i, &r = i; // 合法
练习2.28
说明下面的这些定义是什么意思,挑出其中不合法的。
解:
//const修饰的变量必须初始化,无论是内置类型还是指针。
int i, *const cp; // 不合法, const 指针必须初始化
int *p1, *const p2; // 不合法, const 指针必须初始化
const int ic, &r = ic; // 不合法, const int 必须初始化
const int *const p3; // 不合法, const 指针必须初始化
const int *p; // 合法. 一个指针,指向 const int
练习2.29
假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。
解:
i = ic; // 合法, 常量赋值给普通变量
p1 = p3; // 不合法, p3 是const指针不能赋值给普通指针
p1 = ⁣ // 不合法, 普通指针不能指向常量
p3 = ⁣ // 不合法, p3 是常量指针且指向常量, 故p3 不能被修改, 本句赋值语句正在修改
p2 = p1; // 不合法, p2是常量指针, 有顶层const, 不能被修改
ic = *p3; // 不合法, 对 p3 取值后是一个 int 然后赋值给 ic, 但ic是常量不能被修改
对于p1 = p3:
int i = 0;
const int *const p3 = &i;
int *p1;
p1 = p3;
错误出在第一个const上,因为编译器不知道p3指向的到底是常量还是变量,因此默认p3指向的是一个常量整数。所以p3不能乱赋值给一个非常量的int指针。
因此,编译器会报错,指出不能将const int *const类型的指针赋值给int*类型的指针,因为它们的常量性不匹配。
顶层const
顶层const
:指针本身是个常量。底层const
:指针指向的对象是个常量。拷贝时严格要求相同的底层const资格。
练习2.30
对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?
const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
解:
v2 是顶层const,p2 是底层const,p3 既是顶层const又是底层const,r2 是底层const。
练习2.31
假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。
解:
r1 = v2; // 合法, 顶层const在拷贝时不受影响
p1 = p2; // 不合法, p2 是底层const,如果要拷贝必须要求 p1 也是底层const
p2 = p1; // 合法, int* 可以转换成const int*
p1 = p3; // 不合法, p3 是一个底层const,p1 不是
p2 = p3; // 合法, p2 和 p3 都是底层const,拷贝时忽略掉顶层const
constexpr
和常量表达式(▲可选)
- 常量表达式:指值不会改变,且在编译过程中就能得到计算结果的表达式。
字面值属于常量表达式,用字面值初始化的const对象也是常量表达式。
C++11
新标准规定,允许将变量声明为constexpr
类型以便由编译器来验证变量的值是否是一个常量的表达式。
#include<iostream>
#include<string>
int main(void)
{
int i = 1;
constexpr int &i2 = i; //报错,i不是常量表达式
std::cout<<i2<<std::endl;
i++;
std::cout<<i2<<std::endl;
return 0;
}
#include<iostream>
#include<string>
int main(void)
{
int i = 1;
const int &i2 = i; //成功运行
std::cout<<i2<<std::endl;
i++;
std::cout<<i2<<std::endl;
return 0;
}
- 指针的constexpr
练习2.32
下面的代码是否合法?如果非法,请设法将其修改正确。
int null = 0, *p = null;
解:
非法,即使int的值恰好是0,也不能直接给指针赋值int变量。应改为
int null = 0, *p = &null;
而且应该注意到,null都是小写,并不是关键字或者预处理变量。
处理类型
类型别名
- 传统别名:使用typedef来定义类型的同义词。
typedef double wages;
- 新标准别名:别名声明(alias declaration):
using SI = Sales_item;
(C++11)
// 对于复合类型(指针等)不能代回原式来进行理解
typedef char *pstring; // pstring是char*的别名
const pstring cstr = 0; // 指向char的常量指针
// 如改写为const char *cstr = 0;不正确,为指向const char的指针
// 辅助理解(可代回后加括号)
// const pstring cstr = 0;代回后const (char *) cstr = 0;
// const char *cstr = 0;即为(const char *) cstr = 0;
auto类型说明符 c++11
- auto类型说明符:让编译器自动推断类型。
- 一条声明语句只能有一个数据类型,所以一个auto声明多个变量时只能相同的变量类型(包括复杂类型&和*)。
auto sz = 0, pi =3.14//错误
- 会忽略引用:
int i = 0, &r = i; auto a = r;
推断a
的类型是int
,因为r实际是指向i的,r只是i的一个别名。
#include <iostream>
#include<stdio.h>
#include<string>
#include<sstream>
#include<boost/type_index.hpp>
using boost::typeindex::type_id_with_cvr;
int main()
{
int i = 100;
const int& refI = i;
auto i2 = refI;
//输出int
std::cout << type_id_with_cvr<decltype(i2)>().pretty_name() << std::endl;
return 0;
}
- 会忽略
顶层const
。
auto关键字在推断类型时,如果没有引用符号,会忽略值类型的const修饰,而保留修饰指向对象的const,典型的就是指针。
会忽略第二个const而保留第一个const
即会忽略顶层const
,而保留底层const
即pi2的类型是const int *
理解:auto pi2 = pi;
此时pi2与pi指向同一块地址,但当pi2发生变化,比如指向下一块地址时,不会影响到pi仍然指向原地址。所以const修饰符被忽略。
而因为pi2有直接修改原地址(i=100所在的地址)中i的值的能力,为了防止pi2对const类型i进行修改,所以pi2的类型为const int*,即i为const
运行结果:const int *
const int ci = 1; auto f = ci;
推断类型是int
,如果希望是顶层const需要自己加const
,const auto f = ci
个人理解:
auto f = ci; //值传递,f没能力改变ci的值,因此auto推断出来的类型不带const
const int ci = 1;
auto &f = ci;
std::cout << type_id_with_cvr<decltype(f)>().pretty_name() << std::endl; //此时则为const int &
练习2.35
判断下列定义推断出的类型是什么,然后编写程序进行验证。
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;
解:
j 是 int,k 是 const int的引用,p 是const int *,j2 是const int,k2 是 const int 的引用。
decltype类型指示符
- 从表达式的类型推断出要定义的变量的类型。
9
- decltype:选择并返回操作数的数据类型。
decltype(f()) sum = x;
推断sum
的类型是函数f
的返回类型。- 不会忽略
顶层const
。 - 如果对变量加括号,编译器会将其认为是一个表达式,如int i-->(i),则decltype((i))得到结果为int&引用。
- 赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果 i 是 int,则表达式 i=x 的类型是 int&。
C++11
decltype和auto的区别
decltype
和auto
是C++11引入的两个类型推导机制,用于在编译时自动推导变量的类型。尽管它们可以实现类似的功能,但它们有以下区别:
推导的对象不同:
decltype
:decltype
从表达式中推导出变量的类型。它可以获取变量、函数调用、表达式等的类型,包括修饰符和引用。auto
:auto
用于推导变量的初始值表达式的类型。它根据变量初始化的值来确定类型,并且通常会忽略顶层的const
和引用修饰符。
推导时机不同:
decltype
:decltype
在编译时对表达式进行推导,因此可以用于推导尚未初始化的变量的类型。auto
:auto
在编译器遇到变量声明时进行推导,要求变量必须被初始化,以便从初始值推导出类型。
引用和顶层
const
的处理不同:decltype
:decltype
保留变量的引用和顶层const
限定符。auto
:auto
推导的类型会去除引用和顶层const
限定符,得到非引用类型。
下面是一些示例代码,用于展示decltype
和auto
的区别:
int x = 10;
const int& ref = x;
decltype(ref) a = x; // 推导为 const int&
auto b = ref; // 推导为 int
decltype(x + 1) c = x; // 推导为 int
auto d = x + 1; // 推导为 int
decltype((x)) e = x; // 推导为 int&
auto f = (x); // 推导为 int,去除了引用修饰符
decltype(x) g; // 正确,推断为未初始化的int类型,decltype不需要初始化表达式
auto h; // 编译错误,auto 需要初始化表达式
综上所述,decltype
和auto
在类型推导时有一些区别:
表达式类型推导能力:
decltype
能够推导出表达式的准确类型,包括修饰符和引用。auto
只能根据初始值的表达式推导出变量的类型,不考虑修饰符和引用。
引用和顶层
const
的处理:decltype
会保留变量的引用和顶层const
限定符。auto
会去除引用和顶层const
限定符。
推导时机:
decltype
在编译时对表达式进行推导,可以用于推导尚未初始化的变量的类型。auto
在编译器遇到变量声明时进行推导,要求变量必须被初始化。
使用场景:
decltype
通常用于需要获取表达式类型的情况,比如模板元编程或函数返回类型推导。auto
通常用于简化代码书写,尤其是在迭代器、范围循环等场景下,让编译器自动推导类型。
需要注意的是,由于auto
是在编译时进行类型推导,因此它不能用于推导运行时动态类型的情况,例如函数参数的类型、函数返回类型无法使用auto
进行推导。
练习2.36
练习2.37
自定义数据结构
struct
尽量不要把类定义和对象定义放在一起。如
struct Student{} xiaoming,xiaofang;
- 类可以以关键字
struct
开始,紧跟类名和类体。 - 类数据成员:类体定义类的成员。
C++11
:可以为类数据成员提供一个类内初始值(in-class initializer)。
编写自己的头文件
- 头文件通常包含哪些只能被定义一次的实体:类、
const
和constexpr
变量。
预处理器概述:
- 预处理器(preprocessor):确保头文件多次包含仍能安全工作。
- 当预处理器看到
#include
标记时,会用指定的头文件内容代替#include
- 头文件保护符(header guard):头文件保护符依赖于预处理变量的状态:已定义和未定义。
#indef
已定义时为真#inndef
未定义时为真- 头文件保护符的名称需要唯一,且保持全部大写。养成良好习惯,不论是否该头文件被包含,要加保护符。
#ifndef SALES_DATA_H //SALES_DATA_H未定义时为真
#define SALES_DATA_H
strct Sale_data{
...
}
#endif
C++头文件保护符(Header Guard)是一种预处理指令,用于防止头文件被多次包含。当多个源文件包含同一个头文件时,头文件保护符确保头文件只会被编译一次,避免重复定义错误。
通常情况下,头文件保护符使用宏来实现。以下是一个常见的头文件保护符的示例:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// 头文件内容
#endif
这里的HEADER_NAME_H
是一个唯一的标识符,可以是任何合法的C++标识符。当编译器首次遇到#ifndef
指令时,如果HEADER_NAME_H
未定义,则继续编译头文件,并定义HEADER_NAME_H
。如果HEADER_NAME_H
已定义,则跳过头文件内容,避免重复编译。
头文件保护符的工作原理如下:
#ifndef
检查指定的标识符是否已定义。- 如果标识符未定义(即第一次包含头文件),则执行
#define
指令来定义该标识符,并继续编译头文件内容。 - 如果标识符已定义(即头文件已经被包含过),则跳过头文件内容,避免重复编译。
- 最后,通过
#endif
指令结束头文件保护符的区域。
使用头文件保护符可以确保头文件只被编译一次,提高编译效率并避免重复定义错误。它是编写C++头文件时的常见做法。
【C++ Primer】第二章(2 ~ 6节)的更多相关文章
- C++PRIMER第二章前半部分答案
C++PRIMER第二章前半部分答案 哈哈哈,为什么是前半部分呢,后半部分还在学习中,重新系统性的学习c++,共同进步嘛,不多说,跟我一起来看看吧,第三章开始才是新手收割的时候,慢慢来~~ 2.1&a ...
- 张恭庆编《泛函分析讲义》第二章第2节 $Riesz$ 定理及其应用习题解答
在本节中, $\scrH$ 均指 $Hilbert$ 空间. 1.在极大闭子空间的交的最佳逼近元 设 $f_1,f_2,\cdots,f_n$ 是 $\scrH$ 上的一组线性有界泛函, $$\bex ...
- 张恭庆编《泛函分析讲义》第二章第4节 $Hahn$-$Banach$ 定理习题解答
1.次线性泛函的性质 设 $p$ 是实线性空间 $\scrX$ 上的次线性泛函, 求证: (1)$p(0)=0$; (2)$p(-x)\geq -p(x)$; (3)任意给定 $x_0\in \scr ...
- 张恭庆编《泛函分析讲义》第二章第5节 共轭空间 $\bullet$ 弱收敛 $\bullet$ 自反空间习题解答
1.$\ell^p\ (1\leq p<\infty)$ 的对偶 求证: $\dps{\sex{\ell^p}^*=\ell^q\quad\sex{1\leq p<\infty,\ \fr ...
- C++primer第二章
第二章 :变量和基本类型 2.1 基本内置类型 C++定义了一套包含算术类型(arithmetic type)和空类型(void)在内的基本数据类型 2.1.1 算术类型 算术类型的分类: 整型(in ...
- [C++Primer] 第二章 变量和基本类型
第二章 变量和基本类型 引用 引用定义的时候必须初始化. 引用初始化之后无法重新绑定到其它对象上. 引用本身并不是对象,所以没有指向引用的引用(不管如何多层引用,引用的还是源对象) 下面用一个简单的例 ...
- C++ Primer : 第二章:变量和基本类型(1)
变量和基本类型之第一篇:基本内置类型和变量 一. (1) C++定义了一套包括算数类型和空类型,这些类型有:布尔类型bool,字符类型char,宽字符类型wchar_t,Unicode字符char16 ...
- <<C++ Primer>> 第二章 变量和基本类型 术语表
术语表 第 2 章 变量和基本类型 地址(address): 是一个数字,根据它可以找到内存中的一个字节 别名生命(alias declaration): 为另一种类型定义一个同义词:使用 &q ...
- .net架构设计读书笔记--第二章 第7节 神化般的业务层
一.编排业务逻辑的模式1. 事务脚本模式TS(The Transaction Script pattern ) TS模式概述 TS 鼓励你跳过任何的面向对象的设计,你直接到所需的用户操作的业务 ...
- C++Primer 第二章
//1.程序尽量避免依赖于实现环境的行为.比如:如果将int的尺寸看成一个确定不变的已知值,那么这样的程序就称为不可移植的. typedef int int32; //使用类似的typedef,可以有 ...
随机推荐
- 在 Vue 中控制表单输入
Vue中v-model的思路很简单.定义一个可响应式的text(通常是一个ref),然后用v-model="text"将这个值绑定到一个input上.这就创造了一个双向的数据流: ...
- 超详细!手把手教你用 JaCoCo 生成单测覆盖率报告!
我们都知道 Spock 是一个单测框架,其特点是语法简明.但当我们使用 Spock 写了一堆单元测试之后,如何生成对应的单测覆盖率报告呢?一般来说,我们会使用两个插件来一起完成单测覆盖率报告的生成,分 ...
- 使用drf的序列化类实现增删改查接口
目录 什么是DRF 安装DRF 基于原生创建五个接口 基于rest_framework的增删改查 查询多条数据 流程 创建表 创建序列化类 创建视图类 增加路由 查询单条数据 序列化类不变 视图类定义 ...
- [Linux]Linux执行sh脚本时,出现$‘\r‘: command not found(未找到命令)"错误的解决方案[转载]
1 文由 为什么要把这么一个看似很简单的问题,还要以[转载]的方式专门用博客写出来? 主要是在编写crontab的自动化定时脚本的过程中,发现是这个错导致的自动化脚本频繁执行异常时,已经花了好几个小时 ...
- 1.UML之类图
前言 在实际软件开发中,很多人都忽视了先设计后编码的理念,特别是像我这样的新手菜鸟:但在我亲戚的指导下,我便开启了一个简单项目的先设计关卡. 今天的重中之重---UML,学习了它,我们在编写项目代码时 ...
- 五月九号java基础知识点
1.哈希集合元素不按顺序排序,若要排序使用LinkedHashSet类2.树集合类不仅实现Set接口,还实现java.lang.SortedSet接口来实现排序操作3.TreeSet<Strin ...
- ARM Cortex-M4|非常好用的一种串口收发方式
在这里分享项目中我经常使用的一种串口收发方式:阻塞发送 + 接收中断 +空闲中断 + 环形队列 项目代码地址:www.baidu.com 一.简介 串口发送使用最简单的阻塞发送方式,一般来说都是接收的 ...
- Amazon S3 对象存储Java API操作记录(Minio与S3 SDK两种实现)
缘起 今年(2023年) 2月的时候做了个适配Amazon S3对象存储接口的需求,由于4月份自学考试临近,一直在备考就拖着没总结记录下,开发联调过程中也出现过一些奇葩的问题,最近人刚从考试缓过来顺手 ...
- 如何通过C#/VB.NET代码将PowerPoint转换为HTML
利用PowerPoint可以很方便的呈现多媒体信息,且信息形式多媒体化,表现力强.但难免在某些情况下我们会需要将PowerPoint转换为HTML格式.因为HTML文档能独立于各种操作系统平台(如Un ...
- Prism Sample 21-PassingParameters
这个例子是说明导航中传递参数,类似Asp.net中实现. 例子的模板,是例16中使用regionContext实现过的.在例16中, <Grid x:Name="LayoutRoot& ...