??xml version="1.0" encoding="utf-8" standalone="yes"?>
一 const基础
下面四个定义语句是大多数书籍讲解const关键字都会用到的Q?br />
[1]const int* a = &b;
[2]int const *a = &b;
[3]int* const a = &b;
[4]const int* const a = &b;
如果你能区分Zq四U情况,证明你基不错Q不q也不要高兴太早Q这个只是最基础的部分了。不知道也很ҎQ如果const位于星号的左侧(不管const在类型修饰符的左q是叻IQ则const是用来修饰指针所指向的变量,x针指向ؓ帔RQ如果const位于星号的右侧,const是修饰指针本nQ即指针本n是常量。[1]和[2]的情늛同,都是指针所指向的内容ؓ帔RQ这U情况下不允许对内容q行更改操作Q如不能*a = 3 Q这L一U声明方式的作用是可以修改piq个指针所指向的内存地址却不能修Ҏ向对象的|[3]为指针本w是帔RQ而指针所指向的内容不是常量,q种情况下不能对指针本nq行更改操作Q如a++是错误的;[4]为指针本w和指向的内容均为常量?br />
另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中Qconst 可以修饰函数的返回|或某个参敎ͼ对于成员函数Q还可以修饰是整个函数。有如下几种情况Q以下会逐渐的说明用法:
A_class& operator=(const A_class& a); //A_class Z个已l定义的c,下文?br />
void fun0(const A_class* a );
void fun1( ) const; // fun1( ) 为类成员函数
const A_class fun2( );
?const的初始化
先看一下const变量初始化的情况
1) 非指针const帔R初始化的情况Q?br />
A_class b;
const A_class a = b;
2) 指针(引用)const帔R初始化的情况Q?br />
A_class* d = new A_class();
const A_class* c = d;
或?
const A_class* c = new A_class();
引用Q?
A_class f;
const A_class& e = f; // q样作e只能讉K声明为const的函敎ͼ而不能访问一般的成员函数Q?br />
[思?]Q?以下的这U赋值方法正吗Q?br />
const A_class* c=new A_class();
A_class* e = c;
q种Ҏ不正,因ؓ声明指针的目的是Z对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确Q?br />
[思?]Q?以下的这U赋值方法正吗Q?br />
A_class* const c = new A_class();
A_class* b = c;
q种Ҏ正确Q因为声明指针所指向的内容可变;
?作ؓ参数和返回值的const修饰W?br />
其实Q不论是参数q是q回|道理都是一LQ参C入时候和函数q回的时候,初始化const变量
1 修饰参数的const,?
void fun0(const A_class* a );
void fun1(const A_class& a);
调用函数的时候,用相应的变量初始化const帔RQ则在函C中,按照const所修饰的部分进行常量化Q如形参为const A_class* aQ则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如Ş参ؓconst A_class& aQ则不能对传递进来的引用对象q行改变Q保护了原对象的属性?br />
[注意]Q参数const通常用于参数为指针或引用的情?
2 修饰q回值的constQ如,
const A_class fun2( ); const A_class* fun3( );
q样声明了返回值后Qconst按照"修饰原则"q行修饰Qv到相应的保护作用?br />
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
q回值用const修饰可以防止q样的操作发?
Rational a,b;
Radional c;
(a*b) = c;
一般用const修饰q回gؓ对象本nQ非引用和指针)的情况多用于二目操作W重载函数ƈ产生新对象的时候?br />
[ȝ]一般情况下Q函数的q回gؓ某个对象Ӟ如果其声明为constӞ多用于操作符的重载?br />
通常Q不用const修饰函数的返回值类型ؓ某个对象或对某个对象引用的情c?br />
原因如下Q如果返回gؓ某个对象为constQconst A_class test = A_class 实例Q或某个对象的引用ؓconstQconst A_class& test = A_class实例Q,则返回值具有const属性,则返回实例只能访问类A_class中的公有Q保护)数据成员和const成员函数Qƈ且不允许对其q行赋值操作,q在一般情况下很少用到?br />
[思?]Q?q样定义赋值操作符重蝲函数可以吗?
const A_class& operator=(const A_class& a);
不正;在const A_class::operator=(const A_class& a)中,参数列表中的const的用法正,而当q样q箋赋值的时侯Q问题就出现了:A_class a,b,c:(a=b)=c;因ؓa.operator=(b)的返回值是对a的const引用Q不能再c赋值给const帔R?br />
?cL员函Cconst的?br />
一般放在函C后,形如Q?br />
void fun() const;
如果一个成员函数的不会修改数据成员Q那么最好将其声明ؓconstQ因为const成员函数中不允许Ҏ据成员进行修改,如果修改Q编译器报错,q大大提高了E序的健壮性?br />
?使用const的一些徏?br />
1 要大胆的使用constQ这给你带来无的益处Q但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋|具体可见思考题Q?br />
3 在参C使用const应该使用引用或指针,而不是一般的对象实例Q原因同上;
4 const在成员函C的三U用法(参数、返回倹{函敎ͼ要很好的使用Q?br />
5 不要L的将函数的返回值类型定为const;6除了重蝲操作W外一般不要将q回值类型定为对某个对象的const引用;
#include "string.h"
#include "Decode.h"
#pragma argsused
typedef int (__stdcall *fun_AddFun)(int Data);
HINSTANCE gLib = NULL;
fun_AddFun gFun = NULL;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved){
switch(reason) {
case DLL_PROCESS_ATTACH: {
char tPath[255];
int tSize;
GetModuleFileName(hinst,tPath,255);
tSize = strlen(tPath)-1;
while(tPath[tSize]!='\\') {
--tSize;
}
tPath[tSize+1] = 0;
strcat(tPath,"Test.dll");
gLib = LoadLibrary(tPath);
if(gLib == NULL) {
MessageBox(NULL,tPath,"Load Library Failed",MB_OK);
return;
}
gFun = (fun_AddFun)GetProcAddress(gLib,"AddFun");
}
break;
case DLL_PROCESS_DETACH: {
if(gLib) {
FreeLibrary(gLib);
gLib = NULL;
}
}
break;
}
return 1;
}
JNIEXPORT jint JNICALL Java_Encode_Add (JNIEnv *env, jclass cls, jint a, jint b) {
if(gFun==NULL)
return 0;
else {
int tRe = gFun(100);
return a + b + tRe;
}
}
int __declspec(dllexport) __stdcall fun_x(int a,int b)
{
if(gFun==NULL)
return 0;
else {
int tRe = gFun(100);
return a + b + tRe;
}
}
int main(int argc, char *argv[])
{
char* str = "e:/test/nihao.txt";
FILE *t = fopen(str,"wb+");
char tbuf[10]={0};
fwrite(tbuf,1,100,t);
fclose(t);
system("PAUSE");
return EXIT_SUCCESS;
}
int main()
{
unsigned int eflags1, eflags2 = 0;
unsigned int eax = 0;
unsigned int ebx,ecx,edx;
/**
* 试CPU是否支持CPUID指o?br />
* eflags寄存器的W?1位,如果E序可以清楚/讄它,则说明CPU支持CPUID指o。否则不支持
*/
/* 先取eflags */
asm volatile ("pushf\n\t"
"popl %%eax"
: "=a"(eflags1)
:
: "memory"
);
printf("original eflags is %p\n", eflags1);
/* 把eflags的第21位取反,写回寄存器中 */
asm volatile ("pushl %0\n\t"
"popf"
:
: "g"(eflags1 & ~( eflags1 & (1<<21) ) )
);
/* 查一下现在的eflagsQ确认第21位和最初的值相?*/
asm volatile ("pushf\n\t"
"popl %%eax"
: "=a"(eflags2)
:
: "memory"
);
printf("modified eflags is %p\n", eflags2);
/* 把原来的eflagsD|回?*/
asm volatile ("pushl %0\n\t"
"popf"
:
: "g"(eflags1)
);
/**
* FIXME: Intel文档q没有说Q如果不支持CPUID的话Qclear/set eflags的第21位会有什么错误?br />
* 它只_在不支持CPUID指o的CPU上,?0386Q执行CPUID会生invalid opcode错误
*
* 所以,在这里我们不处理 ??eflags W?1比特p|的情?br />
*/
/**
* eax == 1Q则在eax中返回Family/Model/Stepping{信?br />
* [0:3] stepping
* [4:7] model
* [8:11] family
* [12:13] processor type
* [16:19] extended model ID
* [20:27] extended family ID
*/
asm volatile ("cpuid"
: "=a"(eax)
: "0"(1)
);
// printf("eax is %p\n", eax);
printf("Extended Family\t: %d\n", (0xff00000 & eax) >> 20);
printf("Extended Model\t: %d\n", (0xf0000 & eax) >> 16);
printf("Processor type\t: %d\n", (0x3000 & eax) >> 12);
printf("Family\t\t: %d\n", (0xf00 & eax) >> 8);
printf("Model\t\t: %d\n", (0xf0 & eax) >> 4);
printf("Stepping:\t: %d\n", (0xf & eax));
printf("\n");
/**
* eax == 0x800000000
* 如果CPU支持Brand StringQ则在EAX中返 >= 0x80000004的倹{?br />
*/
asm volatile ("cpuid"
: "=a"(eax)
: "0"(0x80000000)
);
printf("Is CPU support Brand String? %s\n", eax >= 0x80000004? "yes":"no");
printf("\n");
/**
* 如果支持Brand StringQ则EAX?x80000002?x80000004Q每ơ增1QCPUID指oq回Q?br />
* EAX : Processor Brand String
* EBX : Processor Brand String Continued
* ECX : Processor Brand String Continued
* EDX : Processor Brand String Continued
*/
if(eax >= 0x80000004) {
unsigned int brands[4]; //每次的eax、ebx、ecx、edx
unsigned int i;
printf("Brand String\t: ");
for (i = 0x80000002; i <= 0x80000004; i++) {
asm volatile ("cpuid"
: "=a"(brands[0]), "=b"(brands[1]), "=c"(brands[2]), "=d"(brands[3])
: "0" (i)
);
printf("%s", (char *)brands);
}
//FIXME: 打出来的字符串是QIn^Htel(R) Pentium(R^H) D CPU 2.80GHz
//其中^H是个不可见字W,会把它前一个吃?/p>
printf("\n");
}
/**
* eax == 0
* eax : cpuid指o允许的最大eax输入?br />
* ebx : "Genu"
* ecx : "ntel"
* edx : "inel"
*/
asm volatile ("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "0"(0) );
printf("Maximum CPUID Input EAX : %p\n", eax);
char string[128];
snprintf(string, 5, "%s", (char *)&ebx);
snprintf(string + 4, 5, "%s", (char *)&edx);
snprintf(string + 8, 5, "%s", (char *)&ecx);
printf("Vendor\t\t: %s\n", string);
printf("\n");
/**
* eax == 1,
* edx的第18比特?Q则CPU支持serial number
* ?Q则不支持,或者被disabled
* 序列h96位,其中最?2位即是eax的输出倹{应当把它保存下来,然后
* 再设|eax==3, 取剩下的64?br />
*/
asm volatile ("cpuid"
: "=a"(eax), "=d"(edx)
: "a"(1)
);
if ( edx & (1 << 18) ) {
/* serial number supported */
/* edx输出中间32位的序列Pecx输出最?2位的序列?*/
asm volatile ("cpuid"
: "=c"(ecx), "=d"(edx)
: "a"(3)
);
printf("Serial Number\t : %x-%x-%x-%x-%x-%x\n",
eax >> 16, eax << 16, edx >> 16, edx << 16, ecx >> 16, ecx << 16);
} else
printf("Serial Number not supported.\n");
printf("\n");
/**
* eax == 80000006hQ返回L2 Cache的信?br />
*
* ecx[31:16] : L2 Cache size, in Kbytes
* ecx[15:12] : L2 Cache Associativity
* 00h disabled
* 01h direct mapped
* 02h 2-Way
* 04h 4-Way
* 06h 8-Way
* 08h 16-Way
* 0Fh Fully associative
* ecx[7:0] : L2 Cache Line size in bytes
*/
asm volatile ("cpuid"
: "=c"(ecx)
: "a"(0x80000006)
);
printf("L2 Cache Size\t : %dKbytes\n", ( ecx >> 16 ) );
printf("L2 Cache Line Size\t : %dbytes\n", (ecx & 0xff));
printf("L2 Cache Associativity\t : ");
switch ( (ecx & 0xf000) >> 12 )
{
case 0x00:
printf("%s\n", "disabled");
break;
case 0x01:
printf("%s\n", "direct mapped");
break;
case 0x02:
printf("%s\n", "2-Way");
break;
case 0x04:
printf("%s\n", "4-Way");
break;
case 0x06:
printf("%s\n", "8-Way");
break;
case 0x08:
printf("%s\n", "16-Way");
break;
case 0x0f:
printf("Fully associative");
break;
default:
printf("No such entry...\n");
}
printf("\n");
/**
* Input : eax == 4 && ecx == 0
*
* (eax[31:26] + 1) 是该物理处理器package上实现的core CPUs数目
*/
asm volatile ("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "0"(4), "2"(0)
);
printf("Number of Cores on this physical package\t : %d\n", (eax >> 27) + 1 );
printf("\n");
/**
* Input : eax == 1Q则edxq回feature flag
*
*/
return 0;
}
int main(int argc, char *argv[]){
struct ifreq ifreq;
int sock;
if(argc!=2)
{
printf("Usage : ethname\n");
return 1;
}
if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
return 2;
}
strcpy(ifreq.ifr_name,argv[1]);
if(ioctl(sock,SIOCGIFHWADDR,&ifreq)<0)
{
perror("ioctl");
return 3;
}
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
(unsigned char)ifreq.ifr_hwaddr.sa_data[0],
(unsigned char)ifreq.ifr_hwaddr.sa_data[1],
(unsigned char)ifreq.ifr_hwaddr.sa_data[2],
(unsigned char)ifreq.ifr_hwaddr.sa_data[3],
(unsigned char)ifreq.ifr_hwaddr.sa_data[4],
(unsigned char)ifreq.ifr_hwaddr.sa_data[5]);
unsigned char temp = (unsigned char)ifreq.ifr_hwaddr.sa_data[0];
int a = temp;
printf("%02x",a);
return 0;
}