https://en.cppreference.com/
这个网站可以查到C++的标准库的用法。
https://isocpp.org
这个是C++标准组织的网站,可以查看C++的新特性。
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
这个是C++新特性的代码规范指南
https://en.cppreference.com/w/cpp/compiler_support
这里可以查看各个编译器对于新特性的支持程度。
总结下来就是(2019.6):
C++ 11/14基本都支持了。
硬件公司如Cray/Nvidia/Oracle(Sun)/IBM基本不支持C++ 17。
能支持C++2a的就只有gcc、Clang、MSVC和EDG eccp了,其中MSVC支持的特性较少,而其他三者相对更新的比较勤。
https://www.edg.com/
这是EDG的官网。它是一家专门做C++前端的公司。因此,他们的更新和开源项目gcc/Clang一样勤,也就不足为奇了。事实上它的商业模式就是:如果硬件公司没有实力或财力做编译器,那么就购买我的前端好了。
Compiler Explorer是Matt Godbolt创建的一个在线编译网站。支持不同版本的gcc生成不同平台的汇编代码。
官网:
https://godbolt.org/
代码:
https://github.com/compiler-explorer/compiler-explorer
https://lgtm.com/
这是一个代码缺陷检测工具
https://www.fluentcpp.com/
一个教你cpp技巧的网站
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
Bjarne Stroustrup编写的C++编程规范
https://github.com/microsoft/GSL
配合上述规范使用的库,能够发现不合规的代码
https://mp.weixin.qq.com/s/cfBT0wsqzZRwedMO7Qz_vA
“任性”的C语言之父:因拒付论文装订费错失博士学位,论文52年后重见天日(Dennis Ritchie)
https://zhuanlan.zhihu.com/p/257089138
C语言发展史的点点滴滴
https://mp.weixin.qq.com/s/_HG19EqrEQiiRRx2SxB19g
图灵老友写下1000条指令程序,锤炼70年,化身350万行代码飞向火星(Christopher Strachey)
在头文件中定义字符串时,如果该头文件会被多个源文件引用的话,字符串必须被定义为const,否则会有重定义错。当然最好在头文件中只放声明,不要放定义。
使用诸如
#ifndef _COMMON_STRING_
#define _COMMON_STRING_
...
...
...
#endif
解决不了这个问题。因为这段代码解决的是同一个源文件重复包含某个头文件的问题。而这里的问题是不同的源文件包含同一头文件时,产生的重复定义的问题。const关键字保证了同一标识符只会定义一次。
int (*p)[10]
先是*p
起作用,声明一个指针(p肯定是指针了),然后是[10]
(数组声明),则p
是指向10个整形元素组成的数组的指针。——数组指针。
若是int *p[10]
则首先是[ ]
起用,它是一个数组了。然后是*
,所以这个数组元素是指针型的。——指针数组。
引申一下
int a[10];
printf("%x\n",&a);
printf("%x\n",a);
可以看到&a和a的值是相等的,但含义不同。a相当于int *p
,而&a相当于int (*p)[10]
。
类似的
int (*p[])(int)
函数指针数组。
int (*p())[]
返回数组指针的函数。
int *p()[]
字面上可以解释为返回指针数组的函数,不过函数是不能返回数组的。
int *(*a())()
这是一个函数,它没有参数,它的返回值是一个函数指针,这个指针指向的函数,也没有参数,且返回值是int型的指针。
http://blog.csdn.net/van150/archive/2005/12/05/544454.aspx
sizeof进行结构体大小的判断
VC的默认规则基本如上所示,gcc的默认规则就是4字节对齐。
可以比较一下
struct s
{
char a;
double b;
int c;
}
与
struct s
{
char a;
int b;
double c;
}
在各个平台上的sizeof值。
附带说一下如果看到以下的代码片段,也就不要觉得惊奇了。
typedef enum _XXX
{
XXX_0 = 0,
XXX_1 = 1,
XXX_FORCE_DWORD = 0x7FFFFFFF/* 编译器对齐 */
}XXX;
1)编译器选项指定
VC:/Zp
gcc:-fpack-struct
2)代码指定
VC和gcc都可以用#pragma pack(4)
gcc还可以用__attribute__((packed))
有的时候,会使用宏展开的方式定义“伪”函数。
这些“伪”函数有以下特征:
1.不是真正的函数,而是接受参数的宏。
2.形式上与普通函数相同。
为了实现这个功能,教科书上给出的做法是这样的:
#define st(x) do { x } while (0)
#define HAL_DMA_SET_SOURCE( pDesc, src ) \
st( \
pDesc->srcAddrH = (uint8)((uint16)(src) >> 8); \
pDesc->srcAddrL = (uint8)( (uint16)(src) & 0xFF ); \
)
但是do { x } while (0)
在有些编译器上会报warning。最近看Ti的代码的时候,看到了一种更好的办法:
#define st(x) do { x } while (__LINE__ == -1)
#define TO_STRING(expr) # expr
// TO_STRING(hello_world)
#define PRINT_VARIABLE_NAME(var) printf("%s", TO_STRING(var));
int main() {
int number = 10;
PRINT_VARIABLE_NAME(number);
printf(" = %d\n", number);
return 0;
}
#define IMPL_1(str) printf("call impl 1 print:%s\n", str);
#define IMPL_2(str) printf("call impl 2 print:%s\n", str);
#define IMPL(which, str) IMPL_ ## which(str)
int main() {
IMPL(1, "aaaaaa");
IMPL(2, "bbbbbb");
return 0;
}
operator A(){...}
operator
关键字除了用于运算符重载之外,还可用于类型转换。上例是将某类型转换成A类型,由于类型转换的结果是确定的,所以该函数的声明中,不需要声明返回值的类型。
#define ADD_2(a, b) ((a) + (b))
#define ADD_3(a, b, c) ((a) + (b) + (c))
#define ADD_4(a, b, c, d) ((a) + (b) + (c) + (d))
#define GET_OVERLOAD(_1, _2, _3, _4, MACRO, ...) MACRO
// __VA_ARGS__ since C99
// ##__VA_ARGS__ to handle empty variadic
// __VA_OPT__ since C++20
#define ADD(...) GET_OVERLOAD(__VA_ARGS__, ADD_4, ADD_3, ADD_2)(__VA_ARGS__)
int main() {
printf("%d\n", ADD(1, 2));
printf("%d\n", ADD(1, 2, 3));
printf("%d\n", ADD(1, 2, 3, 4));
return 0;
}
__FUNCTION__
& __PRETTY_FUNCTION__
template<typename T>
T add(T x, T y) {
printf("__FUNCTION__ is: %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ is: %s\n", __PRETTY_FUNCTION__);
return x + y;
}
int main() {
add<int>(1, 2);
return 0;
}
虽然这个库很强,但是preprocessor并不是图灵完备的,而C++的模板库/CMake则是图灵完备的。
https://www.boost.org/doc/libs/1_75_0/libs/preprocessor/doc/index.html
The Boost Library Preprocessor Subset for C/C++
strtok函数多用于分割字符串,但它会改变被分割字符串的值。因此,如果该字符串以后还有用的话,需要首先复制该字符串,然后对复制的字符串执行strtok函数。
我是在2003年左右学习C++的,后来直到2009年以前,C++都是我的主要工作语言。但由于本人先学的C语言,所以编程的思想一直是函数式的。完成一项任务,无论用C、C++、Java、C#,还是Matlab、Python,风格都是差不多的。这也是后来我对GTK情有独钟的一个重要的原因。
总的来说,我对C++用的多,但理解的却不深。只对单继承、成员函数的封装、访问之类的概念有一定的认识和使用。多重继承、模板会看不会写。更不必提C++ 03和C++ 11的新特性了。最近因为研究Cocos2d-x,而接触到这些新特性,颇有些感觉到自己已经是老古董了。
不过好在Java语言用的还可以,大部分的C++新特性,学起来倒也难不倒我。
2019.6
本来一直做嵌入式开发,基本都是C语言。奈何现在的高性能并行计算,基本都是C++的天下了。而且Google、ARM之流,其使用策略颇为激进,C++ 11是保底,C++ 14才是主流。
以后真的不敢在简历里写会C++了。。。囧
C++语言为了保持与C语言的兼容性,在语法层面上曾经尽力保持C-like。但随着越来越多内容被加入到C++中,这一要求也越来越难以实现。最终,C++11标准的发布彻底改变了C++语言的面貌,其改变之大甚至让C++11看起来像一门全新的语言。因此,多把C++11后的C++称为“Modern C++”。
C++ 03标准到C++ 11标准之间长达8年的间隙,给了其他语言赶超并诟病C++的机会。一些厂商为了解决C++的问题,也加了不少私货,从而导致了版本兼容性的分裂。
为了解决这个问题,C++标准委员会提出了新的版本发布策略:不再等待某项重要特性的成熟,再集体打包发布。而是成熟一项,发布一项。
所以,可以预见的是,即使没有什么重要新特性,也一定会有C++ 20标准。
当然了,从另一个角度来说,C++ 11有改天换地之效,而之后的升级则有些无足轻重了。
https://mp.weixin.qq.com/s/lTu8OCecwe9iHIn82bWQaA
现代C++教程:高速上手C++11/14/17/20,82页pdf
https://zhuanlan.zhihu.com/p/139515439
c++11新特性,所有知识点都在这了!
https://zhuanlan.zhihu.com/p/165389083
C++14新特性的所有知识点全在这儿啦!
https://zhuanlan.zhihu.com/p/165640868
C++17新特性
https://www.zhihu.com/answer/1813428455
C++20有哪些值得注意的新特性?
1.auto
C++11中引入的auto主要有两种用途:自动类型推断和返回值占位。auto在C++98中,标识临时变量的语义,由于使用极少且多余,在C++11中已被删除。前后两个标准中的auto,完全是两个概念,这点尤其需要注意。
http://blog.csdn.net/huang_xw/article/details/8760403
auto的使用
2.nullprt
http://blog.csdn.net/huang_xw/article/details/8764346
引入nullprt
3.仿函数、lambda表达式和闭包
http://www.cnblogs.com/npbool/p/3434757.html
C++11初探:lambda表达式和闭包
4.C++、Java和C#的lambda表达式的格式
C++
auto func = [=](int x, int y)->int {return x * y;};
Java
Runnable r1 = (int x, int y) -> { return x * y; }
C#
Func<int, int, int> towParams = (x, y) => x * y
// plus sign before lambda
auto lambda = +[] (int a, int b) { return a + b; };
// +[] means func pointer: int (func*)(int a, int b);
您的打赏,是对我的鼓励