C++2
49、i++ ++i 哪个效率高
1 1、对于内置数据类型,以现在的编译器的优化水平,前++和后++没区别的,这个可以通过看汇编代码证明 2 3 2、对于自定义数据类型,像STL,前++的效率要高于后++,所以STL中关于iterator都是前++的
50、int x = -8 unsigned int y = x; y += 8 ze y = 0
原因 y = x 若m = 8 x = ~m + 1 ~m + 1 + m = ~m + m + 1 ~m + m 二进制全都是1 + 1 即为0
51、extern "C"
声明C++调用C的函数
原因 C++支持重载 在编译一个函数时 比如foo(int a, double b) 编译生成的函数可能是_foo_int_double的形式 所以在c++中编译c代码会出现问题 引入extern C之后就不会按C++方式编译了
1 引言 2 C++保留了一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。 3 extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。 4 比如说你用C 开发了一个DLL 库,为了能够让C ++语言也能够调用你的DLL输出(Export)的函数,你需要用extern "C"来强制编译器不要修改你的函数名。 5 6 揭秘extern "C" 7 从标准头文件说起 8 #ifndef __INCvxWorksh /*防止该头文件被重复引用*/ 9 #define __INCvxWorksh 10 11 #ifdef __cplusplus //__cplusplus是cpp中自定义的一个宏 12 extern "C" { //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的 13 #endif 14 15 /**** some declaration or so *****/ 16 17 #ifdef __cplusplus 18 } 19 #endif 20 21 #endif /* __INCvxWorksh */ 22 extern "C"的含义 23 extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。 24 被extern "C"限定的函数或变量是extern类型的; 25 1、extern关键字 26 extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 27 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在链接阶段中从模块A编译生成的目标代码中找到此函数。 28 与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。 29 30 2、被extern "C"修饰的变量和函数是按照C语言方式编译和链接的 31 首先看看C++中对类似C的函数是怎样编译的。 32 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为: 33 void foo( int x, int y ); 34 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。 35 _foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。 例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。 36 同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。 37 38 3、举例说明 39 (1)未加extern "C"声明时的连接方式 40 假设在C++中,模块A的头文件如下: 41 42 // 模块A头文件 moduleA.h 43 #ifndef MODULE_A_H 44 #define MODULE_A_H 45 int foo( int x, int y ); 46 #endif 47 //在模块B中引用该函数: 48 // 模块B实现文件 moduleB.cpp 49 #include "moduleA.h" 50 foo(2,3); 51 实际上,在连接阶段,链接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号! 52 53 (2)加extern "C"声明后的编译和链接方式 54 加extern "C"声明后,模块A的头文件变为: 55 56 // 模块A头文件 moduleA.h 57 #ifndef MODULE_A_H 58 #define MODULE_A_H 59 extern "C" int foo( int x, int y ); 60 #endif 61 在模块B的实现文件中仍然调用foo( 2,3 ),其结果是: 62 63 <1>A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式; 64 65 <2>链接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。 66 67 如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo(int x, int y),则模块B找不到模块A中的函数;反之亦然。 68 69 extern “C”这个声明的真实目的是为了实现C++与C及其它语言的混合编程。 70 71 应用场合 72 C++代码调用C语言代码、在C++的头文件中使用 73 在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理: 74 extern "C" 75 { 76 #include "cExample.h" 77 } 78 而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。 79 /* c语言头文件:cExample.h */ 80 #ifndef C_EXAMPLE_H 81 #define C_EXAMPLE_H 82 extern int add(int x,int y); //注:写成extern "C" int add(int , int ); 也可以 83 #endif 84 85 /* c语言实现文件:cExample.c */ 86 #include "cExample.h" 87 int add( int x, int y ) 88 { 89 return x + y; 90 } 91 92 // c++实现文件,调用add:cppFile.cpp 93 extern "C" 94 { 95 #include "cExample.h" //注:此处不妥,如果这样编译通不过,换成 extern "C" int add(int , int ); 可以通过 96 } 97 98 int main(int argc, char* argv[]) 99 { 100 add(2,3); 101 return 0; 102 } 103 如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C"{}。 104 105 在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型 106 //C++头文件 cppExample.h 107 #ifndef CPP_EXAMPLE_H 108 #define CPP_EXAMPLE_H 109 extern "C" int add( int x, int y ); 110 #endif 111 112 //C++实现文件 cppExample.cpp 113 #include "cppExample.h" 114 int add( int x, int y ) 115 { 116 return x + y; 117 } 118 119 /* C实现文件 cFile.c 120 /* 这样会编译出错:#include "cExample.h" */ 121 extern int add( int x, int y ); 122 int main( int argc, char* argv[] ) 123 { 124 add( 2, 3 ); 125 return 0; 126 } 127 128 文/JasonDing(简书作者) 129 原文链接:http://www.jianshu.com/p/5d2eeeb93590 130 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
52、char a[] 和 char *区别
char *p = "aaaaaaaaaaaaaaaa" //p指向的是常量区 所以是不可改变的
char a[] 是栈区
53、
54、sizeof
short 2 long 4 long long 8
55、sizeof和strlen的区别
1.sizeof是操作符 strlen是函数
2.sizeof 可以传递一个类型 strlen传的必须是char* 并且以0结尾
3.sizeof类型必须加括号 sizeof对象可以不加
4.sizeof 数组不退化 strlen数组退化成指针
char a[] = "123" sizeof(a) = 4
char a[100] = "123" sizeof(a)=100
char *a = "123" sizeof(a) = 4
++++++++++++++++++++++++++++++++数组在函数传递的过程中会退化成指针++++++++++++++++++++++++++++++++++
55、inline函数
inline内联函数的引入是为了代替一部分C语言中的宏定义 那些看起来更像函数的宏定义 因为宏定义仅仅是预处理的时候进行替换 没有类型检测 而且 无法调用类的私有成员
普通函数的调用需要保护现场 指令入栈 函数结束时出战恢复现场的工作 如果函数比较简单 那么函数的调用就会花费很多时间
内敛函数时代码的复制 编译器会把内联函数加入所有调用它的地方
类的成员一般设置为私有的 存取函数一般就设为内联
内联在编译时展开 宏在预处理的时候展开
1 内联函数(inline function与一般的函数不同,它不是在调用时发生控制转移,而是在编译阶段将函数体嵌入到每一个调用该函数的语句块中。内联函数(inline function)与编译器的工作息息相关。编译器会将程序中出现内联函数的调用表达式用内联函数的函数体来替换。 2 内联函数的优点: 3 内联函数是将程序执行转移到被调用函数所存放的内存地址,将函数执行完后,在返回到执行此函数前的地方。这种转移操作需要保护现场、包括进栈等操作,在被调用函数代码执行完后,再恢复现场。但是保护现场和恢复现场需要较大的资源开销。对于一些较小的调用函数来说,若是频繁调用,函数调用过程甚至可能比函数执行过程需要的系统资源更多。所以引入内联函数,可以让程序执行效率更高。 4 内联函数的缺点: 5 如果调用内联函数的地方过多,也可能造成代码膨胀。因为编译器会把内联函数的函数体嵌入到每一个调用了它的地方,重复地嵌入。 6 以下是几种含有内联函数的情况: 7 一、 在类中使用内联函数和不使用内联函数
56、c++程序编译过程
57、指针
58、
arg修改也错误
59、
60、
char a[] 实在栈上分配空间
char *a = "" 是在静态区分配空间 不可改
61、第一个越界 第二个指向静态区或常量区 会崩
62、指针函数和函数指针
63、
64、
65、class 和 struct 的区别:
1 1、在c++中class 默认权限是private的 而 struct是public的 这是我认为他两个的最大的不同 2 3 2、class 可以作为模板template的参数 4 5 3、class可以继承struct struct也可以继承struct 不同点在于class 是私有继承 struct是公有继承
66、类构造函数初始化顺序 //构造函数初始化的顺序跟变量声明的顺序是一致的
1 #include <iostream> 2 using namespace std; 3 class A { 4 public : 5 A(int x) :j(x),i(j){ 6 cout << i << " " << j << endl; 7 } 8 private: 9 int i; 10 int j; 11 }; 12 13 int main() { 14 A a(11); 15 }
67、静态变量相比全局变量 静态成员变量不能在类内部进行初始化 静态成员函数只能访问静态变量
1 静态变量: 2 持久隐藏0区共享 3 不会命名冲突
68、main函数之前还会执行其他函数吗
全局变量的构造函数
69、一个空类中默认会产生哪些成员函数
1 构造函、数析构函数、拷贝构造函数、取址运算 2 3 #include <iostream> 4 using namespace std; 5 class A { 6 7 A() {}; 8 ~A() {}; 9 A(const A &){}; 10 A &operator = (const A &) {}; 11 const A * operator &() const {}; 12 13 };
70、构造函数、析构函数可以被重载吗
可以、不可以
71、构造函数的二义性问题
#include <iostream>
using namespace std;
class A {
public:
A(char *s, int l = 0) {};
A(char *s) {};
~A() {};
};
int main() {
A a("111");
}
以上程序将会无法通过编译 原因是编译器无法区分出选用哪个构造函数
72、在函数内部执行构造函数
1 #include <iostream> 2 using namespace std; 3 struct A { 4 public : 5 int b; 6 A(int x) { 7 b = x; 8 }; 9 A() { 10 A(0); 11 }; 12 }; 13 14 int main() { 15 A a(); 16 cout << a.b << endl; 17 }
只是单纯的产生了一个临时对象
73、explicit构造函数,和普通构造函数
explisic声明的构造函数不能被隐式调用,只能显示调用
74、拷贝构造函数的发生场合
1、用一个对象给另一个对象初始化
2、参数中传入对象
3、返回值返回的对象
75、默认拷贝构造函数的执行顺序
#include <iostream>
using namespace std;
struct A {
public :
int a;
A(int aa) {
cout << "1" << endl;
}
A(const A &aa) {
cout << "2" << endl;
}
~A() {
cout << "3" << endl;
}
};
A fun(A a) {
return a;
};
int main() {
A b = fun(10);
//1 2 3 3
}
#include <iostream>
using namespace std;
struct A {
public :
int a;
A(int aa) {
cout << "1" << endl;
}
A(const A &aa) {
cout << "2" << endl;
}
~A() {
cout << "3" << endl;
}
};
A fun(A a) {
return a;
};
int main() {
A b = fun(10);
A c = fun(b);
//1 2 3
//2 2 3
//3 3
}
1 #include <iostream> 2 using namespace std; 3 4 class A { 5 public : 6 static int num; 7 A() { 8 num++; 9 } 10 ~A() { 11 num --; 12 P(); 13 } 14 void P() { 15 cout << num << endl; 16 } 17 }; 18 int A::num = 0; 19 20 A f(A a) { 21 a.P(); 22 return a; 23 } 24 25 int main() { 26 A a; 27 a.P();//1 28 A b = f(a); //1 0 //在执行f函数的时候会使用拷贝构造函数 29 //-1 -2 30 }
---------------------------------------------------------------------------------------
++