编译器的函数名修饰

合集下载

java里面main函数为什么要用static修饰

java里面main函数为什么要用static修饰

java⾥⾯main函数为什么要⽤static修饰
这学期刚开java,因为之前只写过C++和Python没接触过java,有些写法挺不习惯的,今天写完⼀个程序,run的时候发现提⽰the selection can't be launched.......查了⽹上⼀些资料,虽然不知道具体是不是我以为的这个原因,我main函数没有写static(C++和Python都没这玩意⼉),我想我这⾥应该是这个原因。

如果不是这个原因,欢迎指正。

那么我那时候就在想,为什么我不加static就这样了,于是去查了查static的作⽤:
static 是静态的意思,这个我们在学C和C++⾥⾯就学过。

0.static 修饰的域,我们叫静态域,它是归类所有的,被所有对象所共享,只有⼀个
1.static修饰的区块,域只会初始化⼀次
2.static修饰的域或⽅法,可以直接通过类的名字加上.进⾏调⽤
3.static修饰的⽅法内不能直接使⽤⾮静态成员
static这个字告诉编译器,这个main函数是静态的,储存在静态存储区,在定义以后它就存在了,缺少它的话,编译并不会出错,⽽是在运⾏的时候报错,因为这个时候main这个类并没有实例化,⾃然main⽅法就不能⽤,加上static之后,这个⽅法(main)就变成了静态的,不需要实例化就能⽤,我记得刚开始学C语⾔的时候,我们⽼师说main是⼀个程序的⼊⼝,当时怎么想都没想明⽩,现在看这个例⼦,就可以想得通为什么要加static,main作为⼊⼝,不可能先去实例化⼀个对象去调⽤它,所以他必须可以直接调⽤。

volatile函数

volatile函数

volatile函数Volatile函数是一种在C和C++中使用的修饰符,它告诉编译器不应优化变量的访问。

Volatile函数可以用于保护共享内存,以确保来自多个线程的并发访问不会引起意外的,未预料的结果。

由于编译器优化,它会假设变量仅在被声明时和程序结束时通过程序来访问。

但是在这两个时间点之间,它不去考虑变量是否会被更改,这将导致程序失灵。

要解决此问题,应使用volatile函数将变量标记为“volatile”。

这会告诉编译器不要优化或缓存变量,而是必须在内存中查找变量的正确值。

使用volatile函数时需要格外小心,因为这会严重影响性能。

由于编译器无法缓存变量,因此必须每次读取变量时都要从内存中检索其值。

因此,使用volatile函数时,必须仔细考虑是否真的需要使用它来保护变量,以节省CPU时间。

通常,只有在变量存储在多个线程之间共享的内存中时才需要使用volatile函数。

类似地,如果多个线程都可以访问该变量,则必须将其标记为volatile。

例如,某些多任务系统需要实现全局变量,以跨多个线程共享信息。

这种情况下,必须将全局变量标记为volatile。

另一个常见情况是,多个线程都可以访问指向外部设备的指针,这时必须将该指针标记为volatile,以确保多个线程之间不会发生冲突。

此外,一些单片机系统也使用volatile函数,以确保变量在多个线程之间不会发生冲突。

总的来说,Volatile函数是一种修饰符,它可以用于保护共享内存,以便在多个线程之间不会发生意外的结果。

尽管它可以保证变量的一致性,但它也会增加程序处理时间,因此应该根据具体情况仔细考虑是否真的需要使用它。

extern修饰变量或函数时的作用。

extern修饰变量或函数时的作用。

extern修饰变量或函数时的作用。

在编程中,extern是一个关键字,用于修饰变量或函数,其作用是告诉编译器该变量或函数是在其他地方定义的,需要在当前文件中引用。

通过使用extern关键字,可以实现多个文件之间的变量或函数共享,提高代码的可维护性和可扩展性。

一、extern修饰变量的作用在C语言中,extern可以用于修饰全局变量,以便在不同的文件中共享该变量。

当某个文件需要使用其他文件中定义的全局变量时,可以使用extern关键字来声明该变量,从而在当前文件中引用其他文件中定义的全局变量。

例如,假设有两个文件a.c和b.c,其中a.c定义了一个全局变量num:```c// a.c文件int num = 10;```如果在b.c文件中需要使用a.c中定义的全局变量num,可以在b.c 中使用extern关键字声明该变量:```c// b.c文件extern int num;```通过使用extern关键字声明num变量,b.c文件就可以使用a.c中定义的全局变量num了。

这样,不同的文件就可以共享同一个全局变量,实现了变量的跨文件共享。

二、extern修饰函数的作用在C语言中,extern还可以用于修饰函数,以便在不同的文件中共享该函数。

当某个文件需要调用其他文件中定义的函数时,可以使用extern关键字来声明该函数,从而在当前文件中引用其他文件中定义的函数。

例如,假设有两个文件a.c和b.c,其中a.c定义了一个函数add:```c// a.c文件int add(int a, int b) {return a + b;}```如果在b.c文件中需要调用a.c中定义的函数add,可以在b.c中使用extern关键字声明该函数:```c// b.c文件extern int add(int a, int b);```通过使用extern关键字声明add函数,b.c文件就可以调用a.c中定义的函数add了。

iar ramfunc原理 -回复

iar ramfunc原理 -回复

iar ramfunc原理-回复iar ramfunc原理指的是指令编译器iar systems提供的一种特殊函数修饰符,它可以将函数放置在RAM中运行,从而提高程序的执行效率和响应速度。

本文将一步一步解释iar ramfunc原理。

第一步,了解函数修饰符的作用和原理。

函数修饰符是编程语言中的一种语法标记,用于改变函数的行为或特性。

iar systems开发的编译器中,引入了ramfunc这个特殊的函数修饰符。

一般情况下,程序的函数会被编译器放置在程序的ROM(Read-Only Memory,只读存储器)中运行。

但有些函数的执行时间较长,会占用较多的ROM空间,导致程序的执行效率降低。

ramfunc函数修饰符的作用就是将这些函数放置在RAM (Random Access Memory,随机存储器)中运行,从而加快函数的执行速度。

第二步,理解RAM和ROM的区别。

RAM和ROM是计算机存储器中的两种不同类型,具有不同的特点和用途。

RAM是一种易失性存储器,它可以读写数据,并且在电源断开时数据会丢失。

而ROM是一种只读存储器,只能读取数据,不能写入或修改数据,并且在电源断开时数据不会丢失。

由于RAM的读写速度较快,因此将函数放置在RAM中运行可以提高程序的执行效率和响应速度。

第三步,使用ramfunc函数修饰符。

在编译器iar systems的开发环境中,开发人员可以使用ramfunc修饰符来标记需要放置在RAM中运行的函数。

修饰符的使用方法很简单,只需要在函数的声明或定义前加上__ramfunc 关键字即可。

例如:__ramfunc void myFunction(){函数实现}通过这样的方式,编译器会将这个函数放置在RAM中运行,从而提高函数的执行速度。

需要注意的是,由于RAM的空间有限,因此只适合放置一些执行时间较长的函数。

第四步,注意ramfunc函数修饰符的限制。

虽然ramfunc函数修饰符能够提高函数的执行速度,但它也有一些限制。

Wine学习

Wine学习

一、Wine1、wine 实现了大多数的windows API,集成了winedbg2、windows API1)kernel32.dll允许一个W-process作为debugger 去执行另一个W-process,作为debuggee,包括设置breakpoint,单步执行等等2)DBGHELP.DLL让一个debbuger从任意模块查找符号和类型3、异常解决怎么根据下面信息查找crash原因Unhandled exception: page fault on write access to 0x00000000 in 32-bit code (0x0043369e). Register dump:CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006bEIP:0043369e ESP:0b3ee90c EBP:0b3ee938 EFLAGS:00010246( R- -- I Z- -P- )EAX:00000072 EBX:7b8acff4 ECX:00000000 EDX:6f727265ESI:7ba3b37c EDI:7ffa0000Stack dump:0x0b3ee90c: 7b82ced8 00000000 7ba3b348 7b8844010x0b3ee91c: 7b883cdc 00000008 00000000 7bc36e7b0x0b3ee92c: 7b8acff4 7b82ceb9 7b8acff4 0b3eea180x0b3ee93c: 7b82ce82 00000000 00000000 000000000x0b3ee94c: 00000000 0b3ee968 70d7ed7b 70c500000x0b3ee95c: 00000000 0b3eea40 7b87fd40 7b82d0d0Backtrace:=>0 0x0043369e in elementclient (+0x3369e) (0x0b3ee938)1 0x7b82ce82 CONSOLE_SendEventThread+0xe1(pmt=0x0(nil)) [/usr/src/debug/wine-1.5.14/dlls/kernel32/co nsole.c:1989] in kernel32 (0x0b3eea18)2 0x7bc76320 call_thread_func_wrapper+0xb() in ntdll (0x0b3eea28)3 0x7bc7916e call_thread_func+0x7d(entry=0x7b82cda0, arg=0x0(nil), frame=0xb3eeb18) [/usr/src/debug/wi ne-1.5.14/dlls/ntdll/signal_i386.c:2522] in ntdll (0x0b3eeaf8)4 0x7bc762fe RtlRaiseException+0x21() in ntdll (0x0b3eeb18)5 0x7bc7f3da start_thread+0xe9(info=0x7ffa0fb8) [/usr/src/debug/wine-1.5.14/dlls/ntdll/thread.c:408] in ntdl l (0x0b3ef368)6 0xf7597adf start_thread+0xce() in libpthread.so.0 (0x0b3ef468)0x0043369e: movl %edx,0x0(%ecx)Modules:Module Address Debug info Name (143 modules)PE 340000- 3af000 Deferred speedtreertPE 71930000-719b8000 Deferred shdoclcPE 78130000-781cb000 Deferred msvcr80ELF 79afb000-7b800000 Deferred libnvidia-glcore.so.304.51ELF 7b800000-7ba3d000 Dwarf kernel32<elf>\-PE 7b810000-7ba3d000 \ kernel32ELF 7bc00000-7bcd5000 Dwarf ntdll<elf>\-PE 7bc10000-7bcd5000 \ ntdllELF 7bf00000-7bf04000 Deferred <wine-loader>ELF 7c288000-7c400000 Deferred libvorbisenc.so.2PE 7c420000-7c4a7000 Deferred msvcp80ELF 7c56d000-7c5b6000 Deferred dinput<elf>Threads:process tid prio (all id:s are in hex)00000008 (D) C:\Perfect World Entertainment\Perfect World International\element\elementclient.exe 00000031 0 <==00000035 1500000012 000000021 000000045 000000044 000000043 000000038 1500000037 000000036 1500000034 000000033 000000032 000000027 000000009 00000000e services.exe0000000b 000000020 000000017 000000010 00000000f 0下面信息的含义:000d:Call advapi32.RegOpenKeyExW(00000090,7eb94da0 L"Patterns",00000000,00020019,0033f968) ret=7eb 39af8000d:线程idadvapi32: 被调用模块RegOpenKeyExW:被调用函数后面几个都是参数ret :返回地址4、Useful memory address1)32位linux:0x08000000 0x00400000 0x400000002)16位(增强模式):segment:offsetsegment 如果最低三比特位都是1,就是一个selector,如果最低三笔特除了最低位外都是1,可能是全局内存0x1f7 (0x40320000, 0x0000ffff, r-x) :分别是基地址,最大偏移,访问权限r-x 表示可读可执行实际地址:selector基地址+offset3)16位(标准模式):segment:offsetsegment和offset可以是0~0xffff实际地址:segment×16+offset5、配置1)配置debuger[MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug] 957636538 "Auto"=dword:00000001"Debugger"="winedbg %ld %ld"2)配置winedbg[HKCU\\Software\\Wine\\WineDbg]BreakAllThreadsStartup TRUE:所有线程停止FALSE:第一个线程停止BreakOnCritSectTimeOut TRUE:在临界区超时5分钟停止FALSE:不停止BreakOnAttachBreakOnFirstChance一个异常产生两个debug 事件,或者说两次chancefirst chance:发生异常之后传递给debugger,debugger 要么继续执行(cont),要么交给exception handler chain(pass)last chance:如果没有exception handler 处理异常,会再次传递给debugger,这一次不能passTRUE:两次机会都会处理FALSE :仅仅进入last chance AlwaysShowThunk TRUE:根据名称显示所有thunks FALSE:3)+relay 行为配置可能输出会很多,但可以进行设置[HKCU\\Software\\Wine\\Debug]RelayExclude 列出不需要的输出RelayInclude 仅输出列出的输出怎么知道哪些输出是不需要的?WINEDEBUG=+relay wine appname.exe &>relay.logawk -F'(' '{print $1}' < relay.log | awk '{print $2}' | sort | uniq -c | sort二、WineDbg1、WineDbg表达式同C 格式总体相同,有少量差异。

gcc 函数名修饰

gcc 函数名修饰

gcc 函数名修饰gcc(GNU Compiler Collection)是一个广泛使用的开源编译器套件,在C/C++编程领域有着非常高的知名度和应用率。

在使用gcc编译C/C++代码时,我们经常会遇到一个诸多困扰开发者的问题——函数名修饰。

对于初学者来说,理解函数名修饰的作用和原理是很有必要的。

本文将就此问题进行讲解。

一、什么是函数名修饰函数名修饰,也称为函数名重载,是指在编译阶段,编译器将函数名与参数列表一起编码成一个新的函数名,这种方法称为函数名修饰。

在C++中,函数多态性和函数重载(overloading)特性的实现就与函数名修饰密不可分。

而在C语言中,虽然不支持函数重载,但是编译器仍会对函数名进行修饰。

例如,在C++中,有如下几个函数:```cppvoid func(int a, int b) {}void func(double a, double b) {}void func(char a, char b) {}```这几个函数的函数名都是“func”,但是参数列表却是不同的。

为了能够区分不同的函数,编译器就采用了函数名修饰的方法将这几个函数名进行区分,生成了不同的函数名。

二、为什么要进行函数名修饰在很多编程语言中,函数的名称是可以相同的,但是函数的参数列表必须是不同的,通过函数名修饰可以实现不同名但参数列表相同的函数。

这种技术也是实现C++重载和多态这两个强大特性的核心机制。

从另一个角度来说,由于函数名中包含函数参数信息,所以也会在一定程度上增加代码安全性。

例如,在C++中,我们可以使用重载的方法实现不同类型的加法运算:```cppint add(int a, int b) { return a + b; }double add(double a, double b) { return a + b; }```这就是通过函数名修饰实现重载的一个例子。

三、如何禁用函数名修饰在某些情况下,我们需要禁用函数名修饰,以方便直接使用函数的原名称,如C语言中的一些库函数。

extern“C”有什么作用?

extern“C”有什么作用?

extern“C”有什么作用?Extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。

这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数,加上extren “c”后,C++就能直接调用C函数了。

Extern “C”主要使用正规DLL函数的引用和导出和在C++包含C函数或C头文件时使用。

使用时在前面加上extern “c”关键字即可重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?常考的题目。

从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

重写:是指子类重新定义复类虚函数的方法。

从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。

如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。

那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。

对于这两个函数的调用,在编译器间就已经确定了,是静态的。

也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!重写:和多态真正相关。

当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。

因此,这样的函数地址是在运行期绑定的(晚绑定)。

编写字符串拷备函数har *strcpy(char *strDest, const char *strSrc){if ( strDest == NULL || strSrc == NULL)return NULL ;if ( strDest == strSrc)return strDest ;char *tempptr = strDest ;while( (*st rDest++ = *strSrc++) != ‘\0’);return tempptr。

constexpr修饰函数

constexpr修饰函数

constexpr修饰函数
constexpr是C++11中引入的关键字,用于指示编译器在编译时进行常量表达式求值,以便提高程序的执行效率。

constexpr可以修饰变量、函数以及类成员函数。

在函数上下文中,constexpr可以用于指示函数可以在编译时进行常量表达式求值。

这意味着函数的返回值可以被视为常量,并且可以在编译时进行优化。

要使函数成为constexpr函数,必须满足以下条件:
1. 函数的参数和返回值类型必须是字面类型,即内置类型或者常量表达式构造的数组和结构体类型。

2. 函数体中只能包含一些基本的计算操作或者其他constexpr函数调用,不能有控制流语句(比如if、switch等)和循环语句(比如for、while等)。

3. 函数体中不能使用动态内存分配操作(比如new、delete等)。

constexpr函数用法示例:
c++
constexpr int factorial(int n) {
return (n == 0) ? 1 : n * factorial(n - 1);
}
constexpr int result = factorial(5); 编译时求解
在上面的示例中,factorial函数被声明为constexpr函数,可以在编译时求解,将结果赋值给result变量。

extern修饰函数

extern修饰函数

extern修饰函数在C语言中,extern是一个关键字,用来修饰变量和函数。

当用extern修饰函数时,表示该函数是在其他文件中定义的,当前文件中只是声明了该函数的存在,但并没有具体的实现。

为什么要使用extern修饰函数呢?这是因为在C语言中,一个程序往往由多个源文件组成,每个源文件可以定义自己的函数和变量。

当一个源文件中的函数需要调用另一个源文件中的函数时,就需要使用extern来声明该函数的存在。

使用extern修饰函数的语法格式如下所示:extern 返回值类型函数名(参数列表);其中,返回值类型是函数返回值的类型,函数名是函数的名称,参数列表是函数的参数类型和参数名称。

下面我们通过一个例子来说明extern修饰函数的用法。

假设我们有两个源文件:main.c和func.c。

在main.c中,我们定义了一个函数main,而在func.c中,我们定义了一个函数func。

现在我们想在main函数中调用func函数,就需要使用extern来声明func函数的存在。

我们在main.c中使用extern修饰func函数:extern int func(int num);然后,在main函数中调用func函数:int main(){int result = func(10);printf("The result is %d\n", result);return 0;}接下来,我们在func.c中定义func函数:int func(int num){return num * num;}这样,我们就实现了在main函数中调用func函数的功能。

当我们编译并运行这个程序时,会输出"The result is 100"。

需要注意的是,使用extern修饰函数时,我们只需要声明函数的返回值类型、函数名和参数列表,不需要声明函数体。

函数体应该在定义函数的源文件中实现。

extern修饰函数时,如果函数定义和声明在同一个源文件中,可以省略extern关键字。

CC++编译器-cl.exe的命令选项

CC++编译器-cl.exe的命令选项

C/C++编译器-cl.exe的命令选项和在IDE中编译相比,命令行模式编译速度更快,并可以避免被IDE产生的一些附加信息所干扰。

本文将介绍微软C/C++编译器命令行模式设定和用法。

1、设置环境变量:PA TH=C:\Program Files\Microsoft Visual Studio 8\VC\binINCLUDE=C:\Program Files\Microsoft Visual Studio 8\VC\include LIB=C:\Program Files\Microsoft Visual Studio 8\VC\lib如果提示找不到mspdb80.dll文件,则从C:\Program Files\Microsoft Visual Studio 8\Common7\IDE下拷贝“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件到C:\Program Files\Microsoft Visual Studio 8\VC\bin下即可。

2、命令选项:1) /C:在预处理输出中保留注释语句2) /c:只编译,不连接,相当于在"Build"菜单下选择了"Compile"3) /D:定义常量和宏,与源程序里的#define 有相同效果4) /E:预处理C、C++源文件,将源文件中所有的预编译指令及宏展开,将注释去掉,然后将预处理器的输出拷贝至标准输出设备输出,并且在每个文件的开头和末尾加入#line5) /EH:指定编译器用何种异常处理模型6) /EP:同/E,只是去掉了#line7) /F:设置程序的堆栈大小8) /FA:设置生成何种列表文件(汇编、汇编与机器码、汇编与源码、汇编与机器码以及源码)9) /Fa:指定用/FA设置的列表文件的存放路径及(或)文件名10) /FD:生成文件的相互依赖信息11) /Fd:设置程序数据库文件(PDB)的存放路径及(或)文件名12) /Fe:设置最终可执行文件的存放路径及(或)文件名13) /FI:预处理指定的头文件,与源文件中的#include有相同效果14) /Fm:创建map文件15) /Fo:设置编译后Obj文件的存放路径及(或)文件名16) /Fp:设置预编译文件(pch)的存放路径及(或)文件名17) /FR:生成浏览信息(sbr)文件18) /Fr:同/FR,不同之处在于/Fr不包括局部变量信息19) /G3:为80386处理器优化代码生成20) /G4:为80486处理器优化代码生成21) /G5:为Pentium处理器优化代码生成22) /G6:为Pentium Pro处理器优化代码生成23) /GA:为Windows应用程序作优化24) /GB:为Pentium处理器优化代码生成,使用80386、80486、Pentium、Pentium Pro的混合指令集,是代码生成的默认选项(程序属性选项中Processor对应Blend)25) /GD:为Windows动态库(dll)作优化,此开关在VC6中没有实现26) /Gd:指定使用__cdecl的函数调用规则27) /Ge:激活堆栈检测28) /GF:消除程序中的重复的字符串,并将她放到只读的缓冲区中29) /Gf:消除程序中的重复字符串30) /Gh:在每个函数的开头调用钩子(hook)函数--penter31) /Gi:允许渐进编译32) /Gm:允许最小化rebuild33) /GR:允许运行时类型信息(Run-Time Type Infomation)34) /Gr:指定使用__fastcall的函数调用规则35) /Gs:控制堆栈检测所用内存大小36) /GT:支持用__declspec(thread)分配的数据的fier-safety37) /GX:允许同步异常处理,与/EHsc开关等价38) /Gy:允许编译器将每一个函数封装成COMDA Ts的形式,供连接器调用39) /GZ:允许在Debug build 的时候捕捉Release build的错误40) /Gz:指定使用__stdcall的函数调用规则41) /H:限制外部名字的长度42) /HELP:列出编译器的所有的命令开关43) /I:指定头文件的搜索路径44) /J:将char的缺省类型从signed char改成unsigned char45) /LD:创建一个动态连接库46) /LDd:创建一个Debug版本的动态链接库47) /link:将指定的选项传给连接器48) /MD:选择多线程、DLL版本的C Run-Time库49) /MDd:选择多线程、DLL、Debug版本的C Run-Time库50) /ML:选择单线程版本的C Run—Time库51) /MLd:选择单线程、Debug版本的C Run—Time库52) /MT:选择多线程版本的C Run-Time库53) /MTd:选择多线程、Debug版本的C Run—Time库54) /nologo:不显示程序的版权信息55) /O1:优化使产生的可执行代码最小56) /O2:优化使产生的可执行代码速度最快57) /Oa:指示编译器程序里没有使用别名,可以提高程序的执行速度58) /Ob:控制内联(inline)函数的展开59) /Od:禁止代码优化60) /Og:使用全局优化61) /Oi:用内部函数去代替程序里的函数调用,可以使程序运行的更快,但程序的长度变长62) /Op:提高浮点数比较运算的一致性63) /Os:产生尽可能小的可执行代码64) /Ot:产生尽可能块的可执行代码65) /Ow:指示编译器在函数体内部没有使用别名66) /Ox:组合了几个优化开关,达到尽可能多的优化67) /Oy:阻止调用堆栈里创建帧指针68) /Q1f:对核心级的设备驱动程序生成单独的调试信息69) /QI0f:对Pentium 0x0f错误指令作修正70) /Qifdiv:对Pentium FDIV错误指令作修正71) /P:将预处理输出写到指定文件里,文件的后缀名为I72) /TC:将命令行上的所有文件都当作C源程序编译,不管后缀名是否为.c73) /Tc:将指定的文件当作C源程序编译,不管后缀名是否为.c74) /TP:将命令行上的所有文件都当作C++源程序编译,不管后缀名是否为.cpp75) /Tp:将指定文件当作C++源程序编译,不管后缀名是否为.cpp76) /U:去掉一个指定的前面定义的符号或常量77) /u:去掉所有前面定义的符号或常量78) /V:在编译的obj文件里嵌入版本号79) /vd:禁止/允许构造函数置换80) /vmb:选择指针的表示方法,使用这个开关,在声明指向某个类的成员的指针之前,必须先定义这个类81) /vmg:选择指针的表示方法,使用这个开关,在声明指向某个类的成员的指针之前,不必先定义这个类,但要首先指定这个类是使用何种继承方法82) /vmm:设置指针的表示方法为Single Inheritance and MultipleInheritance83) /vms:设置指针的表示方法为Single Inheritance84) /vmv:设置指针的表示方法为Any class85) /W:设置警告等级86) /w:禁止所有警告87) /X:阻止编译器搜索标准的include 目录88) /Yc:创建预编译头文件(pch)89) /Yd:在所有的obj文件里写上完全的调试信息90) /Y u:在build过程中使用指定的预编译头文件91) /YX:指示编译器若预编译头文件存在,则使用它,若不存在,则创建一个92) /Z7:生成MSC7.0兼容的调试信息93) /Za:禁止语言扩展(Microsoft Extensions to C)94) /Zd:调试信息只包含外部和全局的符号信息以及行号信息95) /Ze:允许语言扩展(Microsoft Extensions to C)96) /Zg:为源文件里面定义的每个函数生成函数原型97) /ZI:生成程序库文件(Pdb)并支持Edit and Continue调试特性98) /Zi:生成程序库文件(pdb),包含类型信息和符号调试信息99) /ZL:从obj文件里去掉缺省的库文件名100) /Zm:设置编译器的内存分配xianzhi101) /Zn:禁止浏览信息文件里面的封装102) /Zp:设置结构成员在内存里面的封装格式103) /Zs:快速检查语法错误--------------------------vc所支持的文件类型1) DSW:全称是Developer Studio Workspace,最高级别的配置文件,记录了整个工作空间的配置信息,她是一个纯文本的文件,在vc创建新项目的时候自动生成2) DSP:全称是Developer Studio Project,也是一个配置文件,不过她记录的是一个项目的所有配置信息,纯文本文件3) OPT:与DSW、DSP配合使用的配置文件,她记录了与机器硬件有关的信息,同一个项目在不同的机器上的opt文件内容是不同的4) CL W:记录了跟ClassWizard相关的信息,如果丢失了clw文件,那么在Class View面板里就没有类信息5) PLG:实际上是一个超文本文件,可以用Internet Explorer打开,记录了Build的过程,是一个日志型文件6) RC:资源描述文件,记录了所有的资源信息,在资源编辑器里作的修改,实际上都是对RC文件的修改7) RC2:附加的资源描述文件,不能直接资源编辑器修改,只能手工添加,可以用来添加额外的资源8) RES:经过资源编辑器编译之后的资源文件,以二进制方式存放9) SBR:编译器生成的浏览信息文件,在代码导航的时候非常有用,她需要在编译时指定/FR或者/Fr开关10) BSC:BSCMAKE.EXE将所有的SBR文件作为输入,经过处理之后输出一个BSC文件,在代码导航的时候实际用到的是BSC 文件11) ILK:当选定渐增型编译连接时,连接器自动生成ILK文件,记录连接信息12) PDB:全称是Program DataBase,即程序数据库文件,用来记录调试信息,是一个相当重要的文件,没有他,程序无法正常调试13) LIB:如果项目输出是Dll的话,一般会输出一个跟项目同名的Lib文件,记录输出的函数信息14) EXP:同Lib,是跟Dll一起生成的输出文件15) PCH:全称是PreCompiled Header,就是预先编译好的头文件,在编译时指定/Y u开关时编译器自动生成VC++编译器中一些常见precompiling 指令介绍我们在利用vc6.0 project wizard生成的代码中,经常看到大量的precompiling指令。

在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?

在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?----转首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。

通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。

例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。

这样,模块B中调用模块A中的函数时,在编译阶段,模块B 虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。

函数被C++编译后在符号库中的名字与C语言的不同。

例如,假设某个函数的原型为:void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。

_foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。

例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。

同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。

用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。

gcc的编译属性和选项

gcc的编译属性和选项

gcc的编译属性和选项1.指定内存默认对其参数:__attribute__((packed)):按⼀字节对其__attribute__((aligned(n))):从此之后默认按n字节对其例如:struct stu{ int a; char b;}__attribute__((packed));struct stu{ int a __attribute__((aligned(16))); char b;};例⼦#include <stdio.h>struct ss{char a __attribute__((aligned(16)));int b;//① __attribute__((aligned(16)));};//②__attribute__((aligned(16)));void main(){int i;printf("%d\n", sizeof(struct ss));struct ss s1 = {0x11, 0x55443322};unsigned char *p = (unsigned char *)&s1;for(i=0; i<sizeof(s1); i++){printf("0x%x\n", *(p+i));}}输出:160x110xd10x980x00x220x330x440x550xe00xfc0x980x00xf40xef0x980x0可以看出:__attribute__((aligned(16)))在哪个域后⾯修饰哪个域(注意仅对此域有效,对其它域⽆效),更改了这个域的实际对齐参数,实际对齐参数决定了此域的起始存储位置,再结合结构体的总⼤⼩必须能整除每⼀个域的最⼤对齐参数,因此可以推出来结构体的⼤⼩和内存的存储关系。

将结构体中注释掉掉的部分加上结构体⼤⼩就是32字节。

若只要③处,设定的只是结构体间对齐,结构体成员的存储顺序不变,只是结构体变长了。

重载和重写的区别

重载和重写的区别

18. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?常考的题目。

从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

重写:是指子类重新定义复类虚函数的方法。

从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。

如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。

那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。

对于这两个函数的调用,在编译器间就已经确定了,是静态的。

也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!重写:和多态真正相关。

当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。

因此,这样的函数地址是在运行期绑定的(晚绑定)。

19. 多态的作用?主要是两个:1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

20. Ado与的相同与不同?除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外,两者没有太多共同之处。

但是Ado使用OLE DB 接口并基于微软的COM 技术,而 拥有自己的 接口并且基于微软的.NET 体系架构。

众所周知.NET 体系不同于COM 体系, 接口也就完全不同于ADO和OLE DB 接口,这也就是说 和ADO是两种数据访问方式。

提供对XML 的支持。

21.New delete 与malloc free 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作。

C++中的函数修饰符深入讲解

C++中的函数修饰符深入讲解

C++中的函数修饰符深⼊讲解前⾔C++博⼤精深,⽽且不断拥抱新的变化。

本⽂简要总结⼀下C++中函数的修饰符,其中部分在实际中极少⽤到。

按修饰符的位置分为函数名前与函数名后两种,以下分别做介绍。

函数名前1、返回值类型返回值类型是C++中定义函数的必备部分,这些修饰符包括void,(unsigned) int,bool等内置基本数据类型和⾃定义类型,也包括修饰返回值const关键字(如const int*),还包括C++11中新增的类型⾃动推导auto关键字。

2、 templatetemplate关键字声明函数是模板函数。

3、 virtualvirtual关键字声明函数是虚函数,可被⼦类覆盖。

4、 inlineinline关键字提⽰编译器应将函数内联。

5、 staticstatic修饰类的成员函数时指⽰函数是静态成员函数,不从属于具体对象;修饰单独的函数时,限定函数的可见范围为本⽂件内。

6、 externextern关键字声明⼀个定义在外部的函数7、 explicitexplicit关键字在C++11新增,只⽤于构造函数,指定构造函数要显式定义,不能隐式转换。

8、 friendfriend关键字声明类的友元函数,在函数内可直接访问对象的私有或受保护成员及成员函数。

9、 constexprC++11中新增,指⽰函数返回常量表达式(可以简单理解为返回字⾯量)。

函数名后置于函数名后的修饰符有两种,第⼀种使⽤等号(=),第⼆种直接修饰。

1、使⽤等号此类较为简单,总共有三种:=0:只能⽤于虚函数,表⽰函数为纯虚函数。

=default:C++11新增,只能⽤于编译器提供默认实现的特殊成员函数,指⽰使⽤默认实现。

=delete:C++11新增,只能⽤于编译器提供默认实现的特殊成员函数,指⽰编译器应该删除该函数的默认实现。

2、直接修饰种类繁多,本⼈已知的修饰符包括:const表⽰函数不会修改对象(或者说调⽤期间对象不变),注意不包括mutable修饰的成员变量,可参考本⼈之前⽂章:。

函数的调用规则(__cdecl,__stdcall,__fastcall

函数的调用规则(__cdecl,__stdcall,__fastcall
__stdcall,__fastcall
关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解。 microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall,如果用vc开发dll给其他语言用,则应该指定__stdcall方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__cdecl方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__stdcall的规则,一定要在函数退出(ret)前恢复堆栈。 1.__cdecl 所谓的C调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的。返回值在EAX中因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时候对这种调用规则的函数生成修饰名的饿时候,仅在输出函数名前加上一个下划线前缀,格式为_functionname。 2.__stdcall 按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,切记:函数自己在退出时清空堆栈,返回值在EAX中。 __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_functionname@number。如函数int func(int a, double b)的修饰名是_func@12。 3.__fastcall __fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@functionname@number。这个和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第一个参数进ECX,第2个进EDX,其他参数是从右向左的入stack。返回仍然通过EAX. 4.__pascal 这种规则从左向右传递参数,通过EAX返回,堆栈由被调用者清除 5.__thiscall 仅仅应用于"C++"成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定 调用约定可以通过工程设置:Setting...\C/C++ \Code Generation项进行选择,缺省状态为__cdecl。 名字修饰约定: 1、修饰名(Decoration name):"C"或者"C++"函数在内部(编译和链接)通过修饰名识别 2、C编译时函数名修饰约定规则: __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个"@"符号和其参数的字节数,格式为_functionname@number,例如 :function(int a, int b),其修饰名为:_function@8 __cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。 __fastcall调用约定在输出函数名前加上一个"@"符号,后面也是一个"@"符号和其参数的字节数,格式为@functionname@number。 3、C++编译时函数名修饰约定规则: __stdcall调用约定: 1)、以"?"标识函数名的开始,后跟函数名; 2)、函数名后面以"@@YG"标识参数表的开始,后跟参数表; 3)、参数表以代号表示: X--void , D--char, E--unsigned char, F--short, H--int, I--unsigned int, J--long, K--unsigned long, M--float, N--double, _N--bool, PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复; 4)、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前; 5)、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如 int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z” void Test2() -----“?Test2@@YGXXZ” __cdecl调用约定:规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。 __fastcall调用约定:规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。 VC++对函数的省缺声明是"__cedcl",将只能被C/C++调用. 注意: 1、_beginthread需要__cdecl的线程函数地址,_beginthreadex和CreateThread需要__stdcall的线程函数地址。 2、一般WIN32的函数都是__stdcall。而且在Windef.h中有如下的定义: #define CALLBACK __stdcall #define WINAPI __stdcall 3、extern "C" _declspec(dllexport) int __cdecl Add(int a, int b); typedef int (__cdecl*FunPointer)(int a, int b); 修饰符的书写顺序如上。 4、extern "C"的作用:如果Add(int a, int b)是在c语言编译器编译,而在c++文件使用,则需要在c++文件中声明:extern "C" Add(int a, int b),因为c编译器和c++编译器对函数名的解释不一样(c++编译器解释函数名的时候要考虑函数参数,这样是了方便函数重载,而在c语言中不存在函数重载的问题),使用extern "C",实质就是告诉c++编译器,该函数是c库里面的函数。如果不使用extern "C"则会出现链接错误。一般象如下使用: #ifdef _cplusplus #define ETERN_C extern "C" #else #define EXTERN_C extern #endif #ifdef _cplusplus extern "C"{ #endif EXTERN_C int func(int a, int b); #ifdef _cplusplus } #endif 5、MFC提供了一些宏,可以使用AFX_EXT_CLASS来代替__declspec(DLLexport),并修饰类名,从而导出类,AFX_API_EXPORT来修饰函数,AFX_DATA_EXPORT来修饰变量 AFX_CLASS_IMPORT:__declspec(DLLexport) AFX_API_IMPORT:__declspec(DLLexport) AFX_DATA_IMPORT:__declspec(DLLexport) AFX_CLASS_EXPORT:__declspec(DLLexport) AFX_API_EXPORT:__declspec(DLLexport) AFX_DATA_EXPORT:__declspec(DLLexport) AFX_EXT_CLASS:#ifdef _AFXEXT AFX_CLASS_EXPORT #else AFX_CLASS_IMPORT 6、DLLMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DLLMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DLLMain。 7、一个DLL在内存中只有一个实例 DLL程序和调用其输出函数的程序的关系: 1)、DLL与进程、线程之间的关系 DLL模块被映射到调用它的进程的虚拟地址空间。 DLL使用的内存从调用进程的虚拟地址空间分配,只能被该进程的线程所访问。 DLL的句柄可以被调用进程使用;调用进程的句柄可以被DLL使用。 DLLDLL可以有自己的数据段,但没有自己的堆栈,使用调用进程的栈,与调用它的应用程序相同的堆栈模式。 2)、关于共享数据段 DLL定义的全局变量可以被调用进程访问;DLL可以访问调用进程的全局数据。使用同一DLL的每一个进程都有自己的DLL全局变量实例。如果多个线程并发访问同一变量,则需要使用同步机制;对一个DLL的变量,如果希望每个使用DLL的线程都有自己的值,则应该使用线程局部存储(TLS,Thread Local Strorage)。

C++中时间与时间戳的转换

C++中时间与时间戳的转换

C++中时间与时间戳的转换C++中时间与时间戳的转换C语言把括号、赋值、强制类型转换等都作为运算符处理。

从而使C语言的运算类型极其丰富,表达式类型多样化。

下面是店铺分享的C++中时间与时间戳的转换,一起来看一下吧。

C++ 中时间与时间戳的转换实例// 设置时间显示格式:NSString *timeStr = @"2011-01-26 17:40:50";[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制。

//设置时区,这个对于时间的处理有时很重要。

//例如你在国内发布信息,用户在国外的另一个时区,你想让用户看到正确的发布时间就得注意时区设置,时间的换算。

//例如你发布的时间为2010-01-26 17:40:50,那么在英国爱尔兰那边用户看到的时间应该是多少呢?//他们与我们有7个小时的时差,所以他们那还没到这个时间呢...那就是把未来的事做了。

NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];[formatter setTimeZone:timeZone];NSDate *date = [formatter dateFromString:timeStr]; //------------将字符串按formatter转成nsdateNSLog(@"date = %@", date);NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式NSLog(@"datenow = %@", datenow);NSString *nowtimeStr = [formatter stringFromDate:datenow];//----------将nsdate按formatter格式转成nsstring,nsstring会显示与当前的时间吻合的串NSLog(@"nowtimeStr = %@", nowtimeStr);// 时间转时间戳的方法:NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];NSLog(@"timeSp:%@",timeSp); //时间戳的值// 时间戳转时间的方法NSDate *confromTimesp = [NSDate dateWithTimeIntervalSince1970:1296035591];NSLog(@"1296035591 = %@",confromTimesp);NSString *confromTimespStr = [formatter stringFromDate:confromTimesp];NSLog(@"confromTimespStr = %@",confromTimespStr);// 时间戳转时间的方法:NSDateFormatter* formatter1 = [[NSDateFormatter alloc] init];[formatter1 setDateStyle:NSDateFormatterMediumStyle];[formatter1 setTimeStyle:NSDateFormatterShortStyle];[formatter1 setDateFormat:@"yyyyMMddHHMMss"];NSDate *date1 = [formatter1 dateFromString:@"1283376197"];NSLog(@"date1:%@",date1);当前时间是:14:41:57C/C++内存管理内存分配方式简介在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

C++调用C函数的方法

C++调用C函数的方法

C++调用C函数的方法我们以前见到extern C这样的语句,只是简单地知道跟外部链接有关,但是没有深刻理解它的意思。

今天继续和一起学习C++调用C函数的方法吧!C++调用C函数的方法首先,为什么要使用extern C修饰符?C++调用其它语言的函数,由于编译器生成函数的机制不一样,所以需要经过特殊处理,才可以调用。

调用C语言的函数,需要在函数声明的地方语句extern C。

如果不使用该语句,在链接的时候,编译器就会报以下这种错误。

Test.obj : error LNK2019: 无法解析的外部符号 void __cdecl DeleteStack(struct _Node *) (?DeleteStack@@YAXPAU_Node@@@Z),该符号在函数 _main 中被引用。

然后是如何使用?应该怎么使用该语句呢?刚开始,我简单地在C++源文件的前面使用该语句声明,但是还是出错,而且是在编译阶段就报错。

error C2732: 链接规范与“DeleteStack”的早期规范冲突。

为什么会出现这个错误呢?因为C++源文件已经引入了C的.头文件,在头文件里,声明该函数时没有extern修饰,而这里有extern 修饰,所以冲突了。

解决的办法有两个。

第1页共9页一。

在C头文件中加上extern修饰符。

直接加,也不行。

因为C源文件也包含了这个头文件,当编译C 源文件时,就会出现错误。

所以,需要一种机制来区分是编译C还是C++文件。

方法如下:#ifdef __cplusplusextern C#endifvoid DeleteStack(Stack stack);因为在编译C++文件时,自动定义预处理器名字__cplusplus,而编译C时,没有该处理器名字。

所以只有编译C++时,才有符号extern “C”。

此外,链接指示extern C有单个和复合两种形式。

以上为单个形式,复合形式可以同时将几个函数声明为extern Cextern C {void DeleteStack(Stack stack);void PrintStack(Stack stack);void Pop(Stack stack);}加上预处理器名字如下:#ifdef __cplusplusextern C {#endifvoid DeleteStack(Stack stack);void PrintStack(Stack stack);void Pop(Stack stack);#ifdef __cplusplus}#endif二。

C++常见面试题30道

C++常见面试题30道

C++常见⾯试题30道1.new、delete、malloc、free关系delete会调⽤对象的析构函数,和new对应free只会释放内存,new调⽤构造函数。

malloc与free是C++/C语⾔的标准库函数,new/delete是C++的运算符。

它们都可⽤于申请动态内存和释放内存。

对于⾮内部数据类型的对象⽽⾔,光⽤maloc/free⽆法满⾜动态对象的要求。

对象在创建的同时要⾃动执⾏构造函数,对象在消亡之前要⾃动执⾏析构函数。

由于malloc/free是库函数⽽不是运算符,不在编译器控制权限之内,不能够把执⾏构造函数和析构函数的任务强加于malloc/free。

因此C++语⾔需要⼀个能完成动态内存分配和初始化⼯作的运算符new,以及⼀个能完成清理与释放内存⼯作的运算符delete。

注意new/delete不是库函数。

2.delete与 delete []区别delete只会调⽤⼀次析构函数,⽽delete[]会调⽤每⼀个成员的析构函数。

在More Effective C++中有更为详细的解释:“当delete操作符⽤于数组时,它为每个数组元素调⽤析构函数,然后调⽤operator delete来释放内存。

”delete与new配套,delete []与new []配套MemTest *mTest1=new MemTest[10];MemTest *mTest2=new MemTest;Int *pInt1=new int [10];Int *pInt2=new int;delete[]pInt1; //-1-delete[]pInt2; //-2-delete[]mTest1;//-3-delete[]mTest2;//-4-在-4-处报错。

这就说明:对于内建简单数据类型,delete和delete[]功能是相同的。

对于⾃定义的复杂数据类型,delete和delete[]不能互⽤。

delete[]删除⼀个数组,delete删除⼀个指针。

VisualC++编译器常用选项设置

VisualC++编译器常用选项设置

Visual C++编译器常用选项设置编译参数的设置。

主要通过IDE的菜单项Project->Settings->C/C++页来完成。

我们可以看到这一页的最下面Project Options中的内容,一般如下:/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_Windows" /D "_AFXDLL" /D "_MBCS" /Fp"Debug/WritingDlgTest.pch" /Yu"stdafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c各个参数代表的意义,可以参考Msdn。

比如/nologo表示编译时不在输出窗口显示这些设置(我们可以把这个参数去掉来看看效果)等等。

一般我们不会直接修改这些设置,而是通过这一页最上面的Category中的各项来完成。

1) General:一些总体设置。

Warning level用来控制警告信息,其中Level 1是最严重的级别;Warnings as errors将警告信息当作错误处理;Optimizations是代码优化,可以在Category的Optimizations项中进行更细的设置;Generate browse info用以生成.sbr文件,记录类、变量等符号信息,可以在Category的Listing Files项中进行更多的设置。

Debug info,生成调试信息:None,不产生任何调试信息(编译比较快);Line Numbers Only,仅生成全局的和外部符号的调试信息到.OBJ文件或.EXE文件,减小目标文件的尺寸;C 7.0- Compatible,记录调试器用到的所有符号信息到.OBJ文件和.EXE文件;Program Database,创建.PDB文件记录所有调试信息;Program Database for "Edit & Continue",创建.PDB文件记录所有调试信息,并且支持调试时编辑。

c++def 导出函数

c++def 导出函数

c++def 导出函数
在C++中,可以使用DEF文件来导出函数。

DEF文件为链接器提供有关被链接程序的导出、属性及其他方面的信息。

下面是DEF文件中导出函数的规则:
1. LIBRARY语句:说明DEF文件相应的DLL。

2. EXPORTS语句:在其后要列出导出函数的名称。

可以在DEF文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用)。

在使用DEF文件导出函数时,需要注意以下几点:
- 在DEF文件中,注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。

- 如果要导出C++文件中的函数,则必须将修饰名放到DEF文件中,或者通过使用外部“C”定义具有标准C链接的导出函数。

- 如果将修饰名放到DEF文件中,则可以通过使用DUMPBIN工具或/MAP链接器选项来获取修饰名。

请注意,编译器产生的修饰名是编译器特定的。

如果将 Visual C++编译器产生的修饰名放到DEF文件中,则链接到DLL的应用程序必须也是用相同版本的 Visual C++生成的,这样调用应用程序中的修饰名才能与DLL的DEF文件中的导出名相匹配。

如果你想了解更多关于C++DEF文件的信息,请继续向我提问。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

函数名字修饰(Decorated Name)方式函数的名字修饰(Decorated Name)就是编译器在编译期间创建的一个字符串,用来指明函数的定义或原型。

LINK程序或其他工具有时需要指定函数的名字修饰来定位函数的正确位置。

多数情况下程序员并不需要知道函数的名字修饰,LINK程序或其他工具会自动区分他们。

当然,在某些情况下需要指定函数的名字修饰,例如在C++程序中,为了让LINK 程序或其他工具能够匹配到正确的函数名字,就必须为重载函数和一些特殊的函数(如构造函数和析构函数)指定名字装饰。

另一种需要指定函数的名字修饰的情况是在汇编程序中调用C或C++的函数。

如果函数名字,调用约定,返回值类型或函数参数有任何改变,原来的名字修饰就不再有效,必须指定新的名字修饰。

C和C++程序的函数在内部使用不同的名字修饰方式,下面将分别介绍这两种方式。

1. C编译器的函数名修饰规则对于__stdcall调用约定,编译器和链接器会在输出函数名前加上一个下划线前缀,函数名后面加上一个“@”符号和其参数的字节数,例如_functionname@number。

__cdecl调用约定仅在输出函数名前加上一个下划线前缀,例如_functionname。

__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,例如@functionname@number2. C++编译器的函数名修饰规则C++的函数名修饰规则有些复杂,但是信息更充分,通过分析修饰名不仅能够知道函数的调用方式,返回值类型,参数个数甚至参数类型。

不管__cdecl,__fastcall还是__stdcall 调用方式,函数修饰都是以一个“?”开始,后面紧跟函数的名字,再后面是参数表的开始标识和按照参数类型代号拼出的参数表。

对于__stdcall方式,参数表的开始标识是“@@YG”,对于__cdecl方式则是“@@Y A”,对于__fastcall方式则是“@@YI”。

参数表的拼写代号如下所示:X--voidD--charE--unsigned charF--shortH--intI--unsigned intJ--longK--unsigned long(DWORD)M--floatN--double_N--boolU--struct....指针的方式有些特别,用PA表示指针,用PB表示const类型的指针。

后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复。

U表示结构类型,通常后跟结构体的类型名,用“@@”表示结构类型名的结束。

函数的返回值不作特殊处理,它的描述方式和函数参数一样,紧跟着参数表的开始标志,也就是说,函数参数表的第一项实际上是表示函数的返回值类型。

参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。

下面举两个例子,假如有以下函数声明:int Function1 (char *var1,unsigned long);其函数修饰名为“?Function1@@YG H PA D K@Z”,而对于函数声明:void Function2();其函数修饰名则为“?Function2@@YGXXZ”。

对于C++的类成员函数(其调用方式是thiscall),函数的名字修饰与非成员的C++函数稍有不同,首先就是在函数名字和参数表之间插入以“@”字符引导的类名;其次是参数表的开始标识不同,公有(public)成员函数的标识是“@@QAE”,保护(protected)成员函数的标识是“@@IAE”,私有(private)成员函数的标识是“@@AAE”,如果函数声明使用了const关键字,则相应的标识应分别为“@@QBE”,“@@IBE”和“@@ABE”。

如果参数类型是类实例的引用,则使用“AA V1”,对于const类型的引用,则使用“ABV1”。

下面就以类CTest为例说明C++成员函数的名字修饰规则:class CTest{......private:void Function(int);protected:void CopyInfo(const CTest &src);public:long DrawText(HDC hdc, long pos, const TCHAR* text, RGBQUAD color, BYTE bUnder, bool bSet);long InsightClass(DWORD dwClass) const;......};对于成员函数Function,其函数修饰名为“?Function@CTest@@AAEXH@Z”,字符串“@@AAE”表示这是一个私有函数。

成员函数CopyInfo只有一个参数,是对类CTest的const引用参数,其函数修饰名为“?CopyInfo@CTest@@IAEXABV1@@Z”。

DrawText是一个比较复杂的函数声明,不仅有字符串参数,还有结构体参数和HDC句柄参数,需要指出的是HDC实际上是一个HDC__结构类型的指针,这个参数的表示就是“PAUHDC__@@”,其完整的函数修饰名为“?DrawText@CTest@@QAEJPAUHDC__@@JPBDUtagRGBQUAD@@E_N@Z”。

InsightClass是一个共有的const函数,它的成员函数标识是“@@QBE”,完整的修饰名就是“?InsightClass@CTest@@QBEJK@Z”。

无论是C函数名修饰方式还是C++函数名修饰方式均不改变输出函数名中的字符大小写,这和PASCAL调用约定不同,PASCAL约定输出的函数名无任何修饰且全部大写。

3.查看函数的名字修饰有两种方式可以检查你的程序中的函数的名字修饰:使用编译输出列表或使用Dumpbin 工具。

使用/FAc,/FAs或/FAcs命令行参数可以让编译器输出函数或变量名字列表。

使用dumpbin.exe /SYMBOLS命令也可以获得obj文件或lib文件中的函数或变量名字列表。

此外,还可以使用undname.exe 将修饰名转换为未修饰形式。

函数调用约定和名字修饰规则不匹配引起的常见问题函数调用时如果出现堆栈异常,十有八九是由于函数调用约定不匹配引起的。

比如动态链接库a有以下导出函数:long MakeFun(long lFun);动态库生成的时候采用的函数调用约定是__stdcall,所以编译生成的a.dll中函数MakeFun 的调用约定是_stdcall,也就是函数调用时参数从右向左入栈,函数返回时自己还原堆栈。

现在某个程序模块b要引用a中的MakeFun,b和a一样使用C++方式编译,只是b模块的函数调用方式是__cdecl,由于b包含了a提供的头文件中MakeFun函数声明,所以MakeFun 在b模块中被其它调用MakeFun的函数认为是__cdecl调用方式,b模块中的这些函数在调用完MakeFun当然要帮着恢复堆栈啦,可是MakeFun已经在结束时自己恢复了堆栈,b模块中的函数这样多此一举就引起了栈指针错误,从而引发堆栈异常。

宏观上的现象就是函数调用没有问题(因为参数传递顺序是一样的),MakeFun也完成了自己的功能,只是函数返回后引发错误。

解决的方法也很简单,只要保证两个模块的在编译时设置相同的函数调用约定就行了。

在了解了函数调用约定和函数的名修饰规则之后,再来看在C++程序中使用C语言编译的库时经常出现的LNK 2001错误就很简单了。

还以上面例子的两个模块为例,这一次两个模块在编译的时候都采用__stdcall调用约定,但是a.dll使用C语言的语法编译的(C语言方式),所以a.dll的载入库a.lib中MakeFun函数的名字修饰就是“_MakeFun@4”。

b包含了a提供的头文件中MakeFun函数声明,但是由于b采用的是C++语言编译,所以MakeFun 在b模块中被按照C++的名字修饰规则命名为“?MakeFun@@YGJJ@Z”,编译过程相安无事,链接程序时c++的链接器就到a.lib中去找“?MakeFun@@YGJJ@Z”,但是a.lib中只有“_MakeFun@4”,没有“?MakeFun@@YGJJ@Z”,于是链接器就报告:error LNK2001: unresolved external symbol ?MakeFun@@YGJJ@Z解决的方法和简单,就是要让b模块知道这个函数是C语言编译的,extern "C"可以做到这一点。

一个采用C语言编译的库应该考虑到使用这个库的程序可能是C++程序(使用C++编译器),所以在设计头文件时应该注意这一点。

通常应该这样声明头文件:#ifdef _cplusplusextern "C" {#endiflong MakeFun(long lFun);#ifdef _cplusplus}#endif这样C++的编译器就知道MakeFun的修饰名是“_MakeFun@4”,就不会有链接错误了。

许多人不明白,为什么我使用的编译器都是VC的编译器还会产生“error LNK2001”错误?其实,VC的编译器会根据源文件的扩展名选择编译方式,如果文件的扩展名是“.C”,编译器会采用C的语法编译,如果扩展名是“.cpp”,编译器会使用C++的语法编译程序,所以,最好的方法就是使用extern "C"。

1.__stdcall以“?”标识函数名的开始,后跟函数名;函数名后面以“@@YG”标识参数表的开始,后跟参数表;参数表以代号表示:X--void ,D--char,E--unsigned char,F--short,H--int,I--unsigned int,J--long,K--unsigned long,M--float,N--double,_N--bool,.... PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复;参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。

其格式为“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”void Test2()-----“?Test2@@YGXXZ”2 __cdecl调用约定:规则同上面的_stdcall 调用约定,只是参数表的开始标识由上面的“@@YG”变为“@@Y A”。

相关文档
最新文档