http://antkillerfarm.github.io/
http://www.cplusplus.com/
这个网站可以查到C++的标准库的用法。
在头文件中定义字符串时,如果该头文件会被多个源文件引用的话,字符串必须被定义为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://linux.chinaitlab.com/c/713810.html
http://dev.yesky.com/393/3007393.shtml
http://blog.csdn.net/apunix/archive/2008/01/14/2043945.aspx
http://blog.csdn.net/van150/archive/2005/12/05/544454.aspx
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))
http://jacob777.blog.sohu.com/106426297.html
有的时候,会使用宏展开的方式定义“伪”函数。
这些“伪”函数有以下特征:
不是真正的函数,而是接受参数的宏。
形式上与普通函数相同。
为了实现这个功能,教科书上给出的做法是这样的:
#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)
我是在2003年以后学习C++的,后来直到2009年以前,C++都是我的主要工作语言。但由于本人先学的C语言,所以编程的思想一直是函数式的。完成一项任务,无论用C、C++、Java、C#,还是Matlab、Python,风格都是差不多的。这也是后来我对GTK情有独钟的一个重要的原因。
总的来说,我对C++用的多,但理解的却不深。只对单继承、成员函数的封装、访问之类的概念有一定的认识和使用。多重继承、模板会看不会写。更不必提C++ 03和C++ 11的新特性了。最近因为研究Cocos2d-x,而接触到这些新特性,颇有些感觉到自己已经是老古董了.
不过好在Java语言用的还可以,大部分的C++新特性,学起来倒也难不倒我。
1.auto关键字
C++11中引入的auto主要有两种用途:自动类型推断和返回值占位。auto在C++98中,标识临时变量的语义,由于使用极少且多余,在C++11中已被删除。前后两个标准的auto,完全是两个概念,这点尤其需要注意。
http://blog.csdn.net/huang_xw/article/details/8760403
2.引入nullprt
http://blog.csdn.net/huang_xw/article/details/8764346
3.仿函数、lambda表达式和闭包
http://www.cnblogs.com/npbool/p/3434757.html
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
有些类库出于兼容性的考虑,仍然保留了对旧函数的支持。但是继续使用这些函数,显然不是作者的初衷。因此,有必要在编译时,给出废弃的提示。
近日浏览cocos2d-x v3的代码,发现可以这样做:
宏定义:
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
#define CC_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#elif _MSC_VER >= 1400 //vs 2005 or higher
#define CC_DEPRECATED_ATTRIBUTE __declspec(deprecated)
#else
#define CC_DEPRECATED_ATTRIBUTE
#endif
宏使用:
CC_DEPRECATED_ATTRIBUTE static TextureCache * getInstance();
class Base
{
public:
void something(Base& b){}
};
int main()
{
Base b;
b.something(Base());
return 0;
}
上面的代码在编译时,会出现如下错误信息:
abc.cpp:12:20: error: no matching function for call to ‘Base::something(Base)’
abc.cpp:12:20: note: candidate is:
abc.cpp:6:7: note: void Base::something(Base&)
abc.cpp:6:7: note: no known conversion for argument 1 from ‘Base’ to ‘Base&’
这是由于Base()
生成的是临时变量,将之赋值给一个non-const的引用是不行的。
解决方法是
void something(const Base& b){}
可以参看下文:
http://stackoverflow.com/questions/20247525/about-c-conversion-no-known-conversion-for-argument-1-from-some-class-to
libc是C语言标准库的简称,它有多种实现。除了最常用的gcc自带的glibc之外,还有musl、uClibc、dietlibc等。
http://www.etalabs.net/compare_libcs.html
这个网址是以上4种libc实现的比较结果。从结果来看,musl比较有投资价值。实际上,最近(2015.5)的OpenWrt项目就已经将libc由uClibc改为musl。我也是因为这个原因,才知道musl的。
当然这个表并不完整,其他的libc可以参见:
https://en.wikipedia.org/wiki/C_standard_library
struct mtd_partition {
const char *name; /* identifier string */
uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */
};
static struct mtd_partition parts[] = {
{name: "boot", offset: 0, size:0x500000,},
{name: "setting", offset: 0x500000, size:0x300000,},
{name: "linux", offset: 0x800000, size:0x500000,},
{name: "config", offset: 0xd00000, size:0x100000,},
{name: "rootfs", offset: 0xe00000, size:0x3200000,},
{name: "app", offset: 0x4e00000, size:0x800000,},
};
static struct resource pxa27x_resource_ohci[] = {
[0] = {
.start = 0x4C000000,
.end = 0x4C00ff6f,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_USBH1,
.end = IRQ_USBH1,
.flags = IORESOURCE_IRQ,
},
};
这些方法虽然不知道是C的那个标准引入的,但是见到有代码这样用。
switch (reg) {
case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR:
return 1;
case TAS5086_INPUT_MUX:
case TAS5086_PWM_OUTPUT_MUX:
return 4;
}
可以用上面的办法,少写一些case语句。
这两天实践了一下怎样在linux下创建动态链接。感觉网上的资料虽然翔实,但仍然有疏漏之处。
1)g++和gcc的区别
本来只想给链接的,以显示这不是我的原创。但是现在的链接失效的也太快了。。。囧
只好拿华丽的分隔符来表示引用的内容。
误区一:gcc只能编译c代码,g++只能编译c++代码
两者都可以,但是请注意:
1.后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;后缀为.cpp的,两者都会认为是c++程序,注意,虽然c++是c的超集,但是两者对语法的要求是有区别的。C++的语法规则更加严谨一些。
2.编译阶段,g++会调用gcc,对于c++代码,两者是等价的,但是因为gcc命令不能自动和C++程序使用的库联接,所以通常用g++来完成链接,为了统一起见,干脆编译/链接统统用g++了,这就给人一种错觉,好像cpp程序只能用g++似的。
误区二:gcc不会定义__cplusplus宏,而g++会
实际上,这个宏只是标志着编译器将会把代码按C还是C++语法来解释,如上所述,如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则,就是已定义。
误区三:编译只能用gcc,链接只能用g++
严格来说,这句话不算错误,但是它混淆了概念,应该这样说:编译可以用gcc/g++,而链接可以用g++或者gcc -lstdc++。因为gcc命令不能自动和C++程序使用的库联接,所以通常使用g++来完成联接。但在编译阶段,g++会自动调用gcc,二者等价。
因此,某些时候编不过去,可以试试换换cc的值。
2)gcc4.1.1下似乎对类型检查严了一些,dlsym返回的void*类型不能转换为相应的函数指针类型,需要强制转换。某些网上的例子在这里编不过去。
3)显式调用时,要注意动态库函数的声明,可能要加extern "C"
才能正常执行。(显式调用是运行时加载,所以编译能过,执行却不对了。)可以用nm命令看看链接库的符号表,以确定问题所在。
4)链接的时候需要注意文件的顺序。
比如下面的例子:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/helloworld/linux_so
gcc -o main_link main_link.c -L. -lhello
这条命令中的main_link.c如果放到-lhello
之后就会出问题。也考虑使用--start-group
和--end-group
之类的链接选项解决链接顺序问题。
cout<//输出十六进制数
cout<//输出八进制数
cout<//输出十进制数
strtok函数多用于分割字符串,但它会改变被分割字符串的值。因此,如果该字符串以后还有用的话,需要首先复制该字符串,然后对复制的字符串执行strtok函数。
在C语言的函数定义上,我们通常用的函数定义方式为ANSI C的函数定义方式。但是在C语言之父创立C语言之时,函数的定义形式并非现在我们所见到的形式。
这种风格被称为K&R风格,多见于一些历史悠久的项目或者老的书籍中。出于兼容性考虑,现代的C编译器仍然支持K&R风格。
详见:
http://blog.chinaunix.net/uid-7426920-id-2627743.html