C/C++笔记

来源:互联网 发布:石家庄网络 编辑:程序博客网 时间:2024/06/06 06:31

1. long类型是32位整数,范围是-0x80000000~0x7fffffff;long long是64位整数,范围是-0x8000000000000000~0x7fffffffffffffff

VC6.0的64位整数分别叫做__int64与unsigned __int64,其范围分别是[-2^63, 2^63)与[0,2^64),即-9223372036854775808~9223372036854775807与0~18446744073709551615(约1800亿亿)。对64位整数的运算与32位整数基本相同,都支持四则运算与位运算等。当进行64位与32位的混合运算时,32位整数会被隐式转换成64位整数。但是,VC的输入输出与__int64的兼容就不是很好了,如果你写下这样一段代码:

1  __int64 a;
2 cin >> a;
3 cout << a;

那么,在第2行会收到“error C2679: binary '>>' : no operator defined which takes a right-hand operand of type '__int64' (or there is no acceptable conversion)”的错误;在第3行会收到“error C2593: 'operator <<' is ambiguous”的错误。那是不是就不能进行输入输出呢?当然不是,你可以使用C的写法:
scanf("%I64d",&a);
printf(
"%I64d",a);
就可以正确输入输出了。当使用unsigned __int64时,把"I64d"改为"I64u"就可以了。
  OJ通常使用g++编译器。其64位扩展方式与VC有所不同,它们分别叫做long long 与 unsigned long long。处理规模与除输入输出外的使用方法同上。对于输入输出,它的扩展比VC好。既可以使用
1long long a;
2cin>>a;
3cout<<a;
也可以使用
scanf("%lld",&a);
printf(
"%lld",a);

使用无符号数时,将"%lld"改成"%llu"即可。

  最后我补充一点:作为一个特例,如果你使用的是Dev-C++的g++编译器,它使用的是"%I64d"而非"%lld"。


2. 如果字符串太长,需要书写到多行时,可在每行末尾加反斜线表示本行未完。

<span style="font-size:12px">string str="This string \is long!"</span>

注意下一行顶格书写,否则会有一堆空格。


3.

幻数——上下文里出现的字面常量。

幻数带来的主要问题是它们没有(抽象)语义。当我们阅读和维护带有幻数的代码时,不得不去一个个地搞清楚每个光秃秃的量到底代表的是什么意思。没错,这样也能勉强度日,但带来的是不必要的精力浪费以及准确性的丧失。

复制代码
 1 //这里的一些10分别代表什么意思?? 2 class Portfolio 3 { 4     //... 5     Contact *contracts_[10]; 6     char id_[10]; 7 }; 8  9 ......10 11 for (int i = 0; i < 10; ++i)12 ...
复制代码

幻数的另一个不那么显而易见的坏处就是它会以意想不到的方式降低它所代表的类型的精度。

例如:4000, 它实际类型是平台相关的。

另一个字面常量带来的潜在威胁来源于它们没有地址。

 

给幻数起一个名字。作为一个指导原则,除了0和1之外,程序里出现的任何数大概都可以算作幻数,它们应该有自己的名字。

复制代码
1 class Portfolio2 {3     //...4     enum {maxContracts = 10, idLen = 10};5     Contact *contracts_[maxContracts ];6     char id_[idLen ];7 };
复制代码

在其所在作用域有着明确含义的枚举常量,有着不占空间,也没有任何运行期成本的巨大优点。

 

把数定义为常数,不要定义为宏。C语言的传统方式是使用#define行来对付幻数。C语言预处理程序是一个强有力的工具,但是它又有些鲁莽。使用宏进行编程是一种很危险的方式,因为宏会在背地里改变程序的词法结构。我们应该让语言去做正确的工作(C预处理命令本身不是C语言的组成部分)。

    在c/c++里,整数常数可以用枚举语句声明。在C++里,任何类型都可以使用const声明的常数:

1 const int MAXROW = 24, MAXCOL = 80;

在Java里,可以用final声明:

1 static final int MAXROW = 24, MAXCOL = 80;

C语言也有const值,但是他们不能用作数组的界。这样,enum就是C中唯一可用的选择了。

4.  '^'  是一种位逻辑运算符,在C/C++中是按位异或键。

5.sizeof 是C语言中判断数据类型或者表达式长度的操作符;不是一个函数,字节数的计算在程序编译时进行,而不是在程序执行的过程中才计算出来。

6.状态机是一种构造程序的常用方法,使得程序永远不会因为等待输入而空闲。状态机通常会用switch/case结构形式编写,标记用来表示何时从现在状态转到下一个状态。状态机也提供了一个更好的方法来改变程序的功能和流程,而不需要重写代码,因为状态可以被加入、改变和移动,且不对其他周围的状态产生影响。

7.按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示:

class String {String ( const char* p ); // 用C风格的字符串p作为初始化值//…}String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(“hello”);
但是有的时候可能会不需要这种隐式转换,如下:
class String {       String ( int n ); //本意是预先分配n个字节给字符串String ( const char* p ); // 用C风格的字符串p作为初始化值//…}
8.按常量引用返回是指,对于返回的对象自身,以后不能修改。
9.复制构造函数在如下情况被调用:声明的同时初始化,按值调用传递,返回对象的值。
10.相对于C风格的数组和指针操作,使用vector和string几乎总是较好的选择,偶尔为优化或兼容C和C++也会在代码中用到一小部分C风格的数组和字符串。
11.函数模板不是真正的函数,而是用以产生函数的公式。
12.在基类和派生类中使用同一名字的成员函数,其行为与数据成员一样:在派生类作用域中派生类成员将屏蔽基类成员。即使函数原型不同,基类成员也会被屏蔽。
13.包含指针动作的类被称为智能指针类。这个类比普通的指针高级,因为如果没有赋初值,可以自动将自身初始化为NULL。
14.字符串创建运算符(#)
#include "stdio.h"#define toString(name) #name#define HAHAint main(){    printf("%s\n",toString(HAHA));}
15.逗号表达式
int a,b;b=(a=1,2);printf("a=%d,b=%d\n",a,b);
则结果为
a=1,b=2
16.关键字restrict
restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式.即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改;这样做的好处是,能帮助编译器进行更好的优化代码,生成更有效率的汇编代码.如 int *restrict ptr, ptr 指向的内存单元只能被 ptr 访问到,任何同样指向这个内存单元的其他指针都是未定义的,直白点就是无效指针。restrict 的出现是因为 C 语言本身固有的缺陷,C 程序员应当主动地规避这个缺陷,而编译器也会很配合地优化你的代码.
17.指针初始化
只有char型指针能初始化为常量(字符串),其他类型指针不能初始化为常量,如下述即错:
int * n = 3;
而下述语句为对:
char * s = "hello";
18.枚举类型的元素数
enum {        LSM6DS3_ACCEL = 0,        LSM6DS3_GYRO,        LSM6DS3_SIGN_MOTION,        LSM6DS3_STEP_COUNTER,        LSM6DS3_STEP_DETECTOR,        LSM6DS3_TILT,        LSM6DS3_SENSORS_NUMB,};
其中
LSM6DS3_SENSORS_NUMB
即为前面定义的传感器的数量。
19.
!!a is 1 if a is non-zero and 0 if a is 0