MS(一)


//1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (365*24*60*60)UL
#define SECONDS_PER_YEAR ((unsigned long)(365*24*60*60))

//2. 写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
#define MIN(a,b)   ( (a) <= (b) ? (a) : (b) )
#define MIN(A,B)  ( (A) <= (B)?  (A) : (B) ) 


5. 用变量a给出下面的定义 
a) 一个整型数(An integer) 
int a; // An integer 

b) 一个指向整型数的指针(A pointer to an integer) 
int *a;// A pointer to an integer 

c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) 
int **a;//A pointer to a pointer to an integer

d) 一个有10个整型数的数组(An array of 10 integers) 
int a[10];//An array of 10 integers

e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) 
int *a[10];//An array of 10 pointers to integers

f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) 
int (*a)[10];//A pointer to an array of 10 integers

g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数
(A pointer to a function that takes an integer as an argument and returns an integer) 
int (*a)(int); //A pointer to a function that takes an integer as an argument and returns an integer

h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
( An array of ten pointers to functions that take an integer argument and return an integer )
int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 



//strcpy 
char *mystrcpy(char *dest, const char *src )
{
	//assert ((dest != NULL)&&(src != NULL))
	if( (src != NULL) && (dest != NULL))
	{
		char *address = dest;
		while ( (*dest++ = *src++) != '\0' );
		
	}else
	{
		return -1;
	}
	
	return address;
}














*****************************************************************************************

下面的一段程序有什么错误:

swap( int* p1,int* p2 )
{
 int *p;
 *p = *p1;
 *p1 = *p2;
 *p2 = *p;
} 


在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在vc++中debug运行时提示错误“access violation”。该程序应该改为:

swap( int* p1,int* p2 )
{
 int p;
 p = *p1;
 *p1 = *p2;
 *p2 = p;
} 

*****************************************************************************************

#include <stdio.h>
#include <iostream>
using namespace std;

#define uchar  unsigned char

void func ( char str[100] )
{
	//int n = sizeof( str );
	cout << sizeof( str ) << endl;
}

int main(void)
{

	int a = 5, b = 7, c; 
	c = a+++b;
	printf("a:%d  b:%d  c:%d\n", a, b, c);

	void *p = malloc( 100 );
	cout << sizeof ( p ) << endl;

	char str1[100];
	cout << sizeof( str1 ) << endl;
	func(str1);

	system("pause");
}

/*
a:6  b:7  c:12
4
100
4
请按任意键继续. . .

*/




*****************************************************************************************

写一个“标准”宏min,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?
least = min(*p++, b); 


解答:
#define min(a,b) ((a) <= (b) ? (a) : (b)) 
min(*p++, b)会产生宏的副作用
(*p++) <= (b)?(*p++):(b)
(*p++) <= (b)?执行完,*p的值已经变化了,返回的*p值是上一个指针指的下一个数值。


*****************************************************************************************

为什么标准头文件都有类似以下的结构? 
#ifndef __incvxworksh
#define __incvxworksh 
#ifdef __cplusplus
extern "c" {
#endif 
/*...*/ 
#ifdef __cplusplus
}
#endif 
#endif /* __incvxworksh */ 

解答:
头文件中的编译宏
#ifndef __incvxworksh
#define __incvxworksh
#endif 
的作用是防止被重复引用。
为了实现c和c++的混合编程,c++提供了c连接交换指定符号extern "c"来解决名字匹配问题,函数声明前加上extern "c"后,则编译器就会按照c语言的方式将该函数编译为_foo,这样c语言中就可以调用c++的函数了。


*****************************************************************************************

编写一个函数,作用是把一个char组成的字符串循环右移n个。
比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh” 


//pstr是指向以'\0'结尾的字符串的指针
//steps是要求移动的n

void loopmove ( char * pstr, int steps )
{
 //请填充...
 } 

<pre name="code" class="cpp">#include <stdio.h>
#include <iostream>
using namespace std;

/*
编写一个函数,作用是把一个char组成的字符串循环右移n个。
比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh” 

//pstr是指向以'\0'结尾的字符串的指针
//steps是要求移动的n

void loopmove ( char * pstr, int steps )
{
 //请填充...
 } 
*/

void loop_move(char *pstr, int steps)
{
	steps = steps % strlen(pstr);//当移动的steps大于字符的长度时,对其长度求模即可

	char temp[1024] = { 0 };

	int str_r = strlen(pstr) - steps; 
	//cout << str_r << endl;

	strcpy(temp, pstr + str_r);//abcdefghi 要移动的字符串的后半部分 hi
	strcpy(temp + steps , pstr);//hiabcdefghi
	temp[strlen(pstr)] = '\0';//hiabcdefg

	//strncpy(temp+steps, pstr, (strlen(pstr)- steps) ); //26,27行等价于该行
	strcpy(pstr,temp);

}

int main(void)
{

	char s[] = "abcdefghi";
	cout << s << endl;
	loop_move(s,2); //loop_move(s,11);
	cout << s << endl;

	system("pause");
}

/*
abcdefghi
hiabcdefg
请按任意键继续. . .
*/


 

steps = steps % strlen(pstr);//当移动的steps大于字符的长度时,对其长度求模即可

****************************************************************************

1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。举一个例子,比如:

数字0x12 34 56 78在内存中的表示形式为:

1)大端模式:

低地址 -----------------> 高地址

0x12  |  0x34  |  0x56  |  0x78

2)小端模式:

低地址 ------------------> 高地址

0x78  |  0x56  |  0x34  |  0x12

/***************************************
1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

1)大端模式:
低地址 -----------------> 高地址
0x12  |  0x34  |  0x56  |  0x78

2)小端模式:
低地址 ------------------> 高地址
0x78  |  0x56  |  0x34  |  0x12


嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。
采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,
而Big-endian模式对操作数的存放方式是从高字节到低字节。
例如
16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

	内存地址
	0x4000
	0x4001

	存放内容
	0x34
	0x12
	而在Big-endian模式CPU内存中的存放方式则为:

	内存地址
	0x4000
	0x4001

	存放内容
	0x12
	0x34
	32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

	内存地址
	0x4000
	0x4001
	0x4002
	0x4003

	存放内容
	0x78
	0x56
	0x34
	0x12
	而在Big-endian模式CPU内存中的存放方式则为:

	内存地址
	0x4000
	0x4001
	0x4002
	0x4003

	存放内容
	0x12
	0x34
	0x56
	0x78


联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性,
轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写

	*****************************************/


#include <stdio.h>
#include <iostream>
using namespace std;


//请写一个c函数,若处理器是big_endian的,则返回0;若是little_endian的,则返回1
int checkCPU()
{
	short a = 0x1234; //short两个字节,char 一个字节
	char *p = (char *)&a;
	if (p[0] == 0x12) //if (*p == 0x12)
	{
		cout << "big_endian " << endl;
		return 0; // big endian
	}
	else
	{
		cout << "little_endian " << endl;
		return 1; //little_endian
	}
}


//写一个C函数,若处理器是Big-endian的,则返回0;若是Little-endian的,则返回1
//union型数据所占的空间等于其最大的成员所占的空间,
//对union型成员的存取都是相对于该联合体基地址的偏移量为0处开始
//即,联合体的访问不论对哪个变量的存取都是从union的首地址位置开始。
int checkSystem()   
{  
	union check  
	{  
		int i;  
		char ch;  
	}c;  
	c.i=1;  
	return (c.ch==1);  
}  


int main(void)
{
	int cpu = checkCPU();
	cout << cpu << endl;
	system("pause");

	return 0;
}

//little_endian
//1
//请按任意键继续. . .



判断系统大小端方法分析与总结  点击打开链接 (转)

问题 :如何用程序确认当前系统的存储模式(大端还是小端)?写一个C函数,若处理器是Big-endian的,则返回0;若是Little-endian的,则返回1。

情况1:利用数组类型

  1. #include <cstdio>  
  2. int checkSystem()  
  3. {  
  4.     char s[]="1000";  
  5.     return (s[0]=='1');  
  6. }  
  7. int main()  
  8. {  
  9.     checkSystem()==1 ? printf("Little-endian/n") : printf("Big-endian/n");  
  10.     return 0;  
  11. }  

情况2:利用位移运算

  1. int i = 1;  
  2. if(1>>32 == 0)  
  3.       cout<<"小端模式"<<endl;  
  4. else  
  5.       cout<<" 大端模式"<<endl;  

 

上述方法正确吗?要理解为什么不正确?

 

因为不要在数值上做文章,而大小端是严格与内存挂钩的东西。如果int a=1; 那么a&1==1一定成立,因为这是从数值角度运算的,已经给用户屏蔽掉了大小端的问题。一定要int a=1; *((char*)(&a)) == 1 ,这样判断才有效。

下面总结一些有效的方法。

方法1:利用union类型 —— 可以利用union类型数据的特点:所有成员的起始地址一致。
 

  1. #include <cstdio>  
  2. int checkSystem()  
  3. {  
  4.     union check  
  5.     {  
  6.         int i;  
  7.         char ch;  
  8.     }c;  
  9.     c.i=1;  
  10.     return (c.ch==1);  
  11. }  
  12. int main()  
  13. {  
  14.     checkSystem()==1 ? printf("Little-endian/n") : printf("Big-endian/n");  
  15.     return 0;  
  16. }  

 

方法2:对int强制类型转换

  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. int main()  
  4. {  
  5.     int i = 1;  
  6.     (*(char *)&i == 1) ? printf("Little-endian/n") : printf("Big-endian/n");  
  7.     system("pause");  
  8.     return 0;  
  9. }  

 

方法3:使用union和宏定义

  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. static union  
  4. {  
  5.     char a[4];  
  6.     unsigned long ul;  
  7. }endian = {{'L''?''?''B'}};  
  8. #define ENDIAN ((char)endian.ul)  
  9.   
  10. int main()  
  11. {  
  12.     printf("%c/n", ENDIAN);  
  13.     system("pause");  
  14.     return 0;  
  15. }  

 

补充: 
大小端模式对union类型数据的影响。

  1. #include <cstdio>  
  2. union  
  3. {  
  4.     int i;  
  5.     char a[2];  
  6. }*p, u;  
  7. int main()  
  8. {  
  9.     p=&u;  
  10.     p->a[0]=0x39;  
  11.     p->a[1]=0x38;  
  12.     printf("%x/n",p->i);// 3839 (hex.)  
  13.     printf("%d/n",p->i);// 111000 00111001=14393 (decimal)  
  14.     return 0;  
  15. }  

 

分析如下图所示:
高地址        低地址
—— —— —— ——   int
0   |   0   |  56  |  57    
—— —— —— ——
               —— ——   char
                56  |   57
               —— ——      
这里需要考虑存储模式:大端模式和小端模式。
大端模式(Big-endian):数据的低字节存放在高地址中。
小端模式(Little-endian):数据的低字节存放在低地址中。
union型数据所占的空间等于其最大的成员所占的空间,对union型成员的存取都是相对于该联合体基地址的偏移量为0处开始,即,联合体的访问不论对哪个变量的存取都是从union的首地址位置开始。因此,上面程序输出的结果就显而易见了。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值