//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:利用数组类型
- #include <cstdio>
- int checkSystem()
- {
- char s[]="1000";
- return (s[0]=='1');
- }
- int main()
- {
- checkSystem()==1 ? printf("Little-endian/n") : printf("Big-endian/n");
- return 0;
- }
情况2:利用位移运算
- int i = 1;
- if(1>>32 == 0)
- cout<<"小端模式"<<endl;
- else
- cout<<" 大端模式"<<endl;
上述方法正确吗?要理解为什么不正确?
因为不要在数值上做文章,而大小端是严格与内存挂钩的东西。如果int a=1; 那么a&1==1一定成立,因为这是从数值角度运算的,已经给用户屏蔽掉了大小端的问题。一定要int a=1; *((char*)(&a)) == 1 ,这样判断才有效。
下面总结一些有效的方法。
方法1:利用union类型 —— 可以利用union类型数据的特点:所有成员的起始地址一致。
- #include <cstdio>
- int checkSystem()
- {
- union check
- {
- int i;
- char ch;
- }c;
- c.i=1;
- return (c.ch==1);
- }
- int main()
- {
- checkSystem()==1 ? printf("Little-endian/n") : printf("Big-endian/n");
- return 0;
- }
方法2:对int强制类型转换
- #include<stdio.h>
- #include<stdlib.h>
- int main()
- {
- int i = 1;
- (*(char *)&i == 1) ? printf("Little-endian/n") : printf("Big-endian/n");
- system("pause");
- return 0;
- }
方法3:使用union和宏定义
- #include<stdio.h>
- #include<stdlib.h>
- static union
- {
- char a[4];
- unsigned long ul;
- }endian = {{'L', '?', '?', 'B'}};
- #define ENDIAN ((char)endian.ul)
- int main()
- {
- printf("%c/n", ENDIAN);
- system("pause");
- return 0;
- }
补充:
大小端模式对union类型数据的影响。
- #include <cstdio>
- union
- {
- int i;
- char a[2];
- }*p, u;
- int main()
- {
- p=&u;
- p->a[0]=0x39;
- p->a[1]=0x38;
- printf("%x/n",p->i);// 3839 (hex.)
- printf("%d/n",p->i);// 111000 00111001=14393 (decimal)
- return 0;
- }
分析如下图所示:
高地址 低地址
—— —— —— —— int
0 | 0 | 56 | 57
—— —— —— ——
—— —— char
56 | 57
—— ——
这里需要考虑存储模式:大端模式和小端模式。
大端模式(Big-endian):数据的低字节存放在高地址中。
小端模式(Little-endian):数据的低字节存放在低地址中。
union型数据所占的空间等于其最大的成员所占的空间,对union型成员的存取都是相对于该联合体基地址的偏移量为0处开始,即,联合体的访问不论对哪个变量的存取都是从union的首地址位置开始。因此,上面程序输出的结果就显而易见了。