C语言不留给下次

一,extern C有什么作用

extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言(而不是C++)的方式进行编译。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。1,主要用在下面的情况:可能有的人比较擅长C语言,而有的人擅长C++,这样的情况下也会有用到。C++代码调用C语言代码。在C++的头文件中使用。被extern "C"修饰的变量和函数是按照C语言方式进行编译和链接的。
2, extern int a; 仅仅是一个变量的声明,其并不是在定义变量a,也并未为a分配空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出错。

3,extern对应的关键字是static,static表明变量或者函数只能在本模块中使用,因此,被static修饰的变量或者函数不可能被extern C修饰。

二,static作用

1、定义全局静态变量:在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点:

(1)在全局数据区内分配内存

(2)如果没有初始化,其默认值为0

(3)该变量在本文件内从定义开始到文件结束可见。

2、定义全局静态变量:在局部变量前面加上关键字static,该局部变量便成了静态局部变量。静态局部变量有以下特点:

(1)该变量在全局数据区分配内存

(2)如果不显示初始化,那么将被隐式初始化为0

(3)它始终驻留在全局数据区,直到程序运行结束

(4)其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

3、定义静态函数:在函数的返回类型前加上static关键字,函数即被定义成静态函数。静态函数有以下特点:

(1)静态函数只能在本源文件中使用。

(2)在文件作用域中声明为inline的函数默认为static

说明:静态成员函数只是一个普通的全局函数,只不过受static限制,它只能在文件所在的编译单位内使用,不能在其他编译单位内使用。

在C++语言中新增了两种作用:定义静态数据成员或静态函数成员

1、定义静态数据成员。静态数据成员有如下特点:

(1)内存分配:在程序的全局数据区分配

(2)初始化和定义:静态数据成员定义时要分配空间,所以不能再类声明中定义

2、定义静态成员函数。静态成员函数与类相联系,不与类的对象相联系。静态成员函数不能访问非静态数据成员。原因很简单,非静态数据成员属于特定的类实例。主要用于对静态数据成员的操作。静态成员函数和静态数据成员都没有this指针。

三,sprintf、fprintf、printf和sscanf、fscanf、scanf

1,scanf是键盘输入,printf是输出打印

2,sscanf和sprintf

sprintf     把多个数据按格式打印在字符数组里形成字符串

sscanf    从字符串中获得多个数字并记录到变量存储区里

atoi        可以把字符串里的整数转换成整数类型

atof        可以把字符串里的浮点数转换成双精度浮点类型

#include <stdio.h>
#include <stdlib.h>
int main() 
{
	char str[20] = {0};
	char ch = 0;
	int num = 0;
	float fnum = 0.0f;
	printf("%d %c %g\n", 34, 'u', 4.2f);
    printf("------------------\n");




     sprintf(str, "%d %c %g", 34, 'u', 4.2f);
	 printf("%s\n", str);
     printf("-------------------\n");
        
	 sscanf(str, "%d %c %g", &num, &ch, &fnum);
	 printf("ch是%c,num是%d,fnum是%g\n", ch, num, fnum);
	
	 printf("-------------------\n");
	 printf("%d\n", atoi("34sdg214"));
	 printf("%lg\n", atof("34.23asd34"));
         

        char my[40]="zhangshijun 1998 85.5hhhkkk";
        char name[14];
        int birth;
        double score;
        sscanf(my, "%s %d %lg", &name, &birth, &score);
        printf("name=%s,birth=%d,score=%lg\n",name,birth,score);
}

3,sscanf和fprintf

sscanf:字符指针,也就是从字符指针中读一个数据,到后面的格式化数据里面去。

struct S
{
	int n;
	double d;
	char name[10];
};
int main()
{
	char arr[100] = { 0 };
	struct S tmp = { 0 };
	struct S s = { 100, 3.14, "zhangsan" };
	//把一个格式化的数据转换成字符串
	sprintf(arr, "%d %lf %s", s.n, s.d, s.name);
	//打印
	printf("%s\n", arr);
	//从arr中的字符串中提取出一个格式化的数据
	sscanf(arr, "%d %lf %s", &(tmp.n), &(tmp.d), tmp.name);
	//打印
	printf("%d %lf %s\n", tmp.n, tmp.d, tmp.name);
	return 0;
}

fprintf:将按格式指向的C字符串写入流。如果格式包括格式说明符(从%开始的子序列),则格式化后的附加参数将被格式化并插入到结果字符串中,替换各自的说明符。 

//fprintf(按某一种格式写入)
struct S
{
	int n;
	double d;
};
int main()
{
	struct S s = { 100, 3.14 };
	FILE* pf = fopen("data.txt", "w");//写入文本文件data.txt
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
	//写文件
	fprintf(pf, "%d %lf", s.n, s.d);
	//关闭文件
	fclose(pf);
	pf = NULL;
}

四,浮点相减或有符号无符号相减

    unsigned int a=10;
    signed int b=-130;
   实验证明b>a,也就是说-130>10,为什么会出现这样的结果呢?

因为在C语言操作中,如果遇到无符号数与有符号数之间的操作,编译器会自动转化为无符号数来进行处理,因此a=10,b=4294967166,这样比较下去当然b>a了。 

五,C语言如何存储浮点类型

C语言和 C#语言中,对于浮点型的数据采用单精度类型(float)和双精度类型(double)来存储:
float 数据占用 32bit;
double 数据占用 64bit;

不论是 float 类型还是 double 类型,在存储方式上都是遵从IEEE的规范:
float 遵从的是 IEEE R32.24;
double 遵从的是 IEEE R64.53;
单精度或双精度在存储中,都分为三个部分:

符号位 (Sign):0代表正数,1代表为负数;
指数位 (Exponent):用于存储科学计数法中的指数数据;
尾数部分 (Mantissa):采用移位存储尾数部分;

8.25  用十进制表示为:8.25 * 10^0

120.5 用十进制表示为:1.205 * 10^2

而计算机根本不认识十进制的数据,只认识0和1。

所以在计算机存储中,首先要将上面的数更改为二进制的科学计数法表示:

8.25   用二进制表示为:1000.01,二进制的科学计数法表示 1000.1,可以表示为1.0001 * 2^3。

118.5 用二进制表示为:1110110.1,二进制科学计数法表示1110110.1,表示为1.1101101 * 2^6。

任何一个数的科学计数法表示都为1. xxx * 2^n ,尾数部分就可以表示为xxxx,由于第一位都是1,所以将小数点前面的1省略。由此,23bit的尾数部分,可以表示的精度却变成了24bit。(float有效位数相应的也会发生变化,而double则不会,因达不到)

六,大端模式和小端模式

1,在计算机中一般讲字节序分为两类:Big-Endian(大端字节序) 和 Little-Endian(小端字节序)。
a) Little-Endian 高位字节在前,低位字节在后。
b) Big-Endian 低位字节在前,高位字节在后。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序

2,在x86的计算机中,一般采用的是小端字节序

#include<stdio.h>                                                                                    
int main()
{
    int b = 0x017f;
    int *p = &b;
    char d = 0 ;
    for(int i = 0;i < 4;i++)
    {
        d = *((char*)p+i);
        printf("d is %d \n",d);    
    }   
}

d is 127
d is 1
d is 0
d is 03,为了避免因为Endianness造成的通信问题,及便于软件开发者编写易于平台移植的程序,特别定义了一些C语言预处理的宏来实现网络字节与主机字节次序之间的相互转换。htons()和htonl()用来将主机字节次序转成网络字节次序,前者应用于16位无符号数,后者应用于32位无符号数。Linux系统中t头文件是netinet/in.h,ntohs()和ntohl()实现反方向的转换。进行转换bsd socket提供了转换的函数有四个:

htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序



typedef unsigned short int uint16;
typedef unsigned long int uint32;
// 短整型大小端互换
#define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | /
                                                 (((uint16)(A) & 0x00ff) << 8))
// 长整型大小端互换
#define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | /
                                                 (((uint32)(A) & 0x00ff0000) >> 8) | /
                                                 (((uint32)(A) & 0x0000ff00) << 8) | /
                                                 (((uint32)(A) & 0x000000ff) << 24))
// 本机大端返回1,小端返回0
int checkCPUendian()
{
       union  

      {
              unsigned long int i;
              unsigned char s[4];
       }c;
       c.i = 0x12345678;
       return (0x12 == c.s[0]);
}
// 模拟htonl函数,本机字节序转网络字节序
unsigned long int HtoNl(unsigned long int h)
{
       // 若本机为大端,与网络字节序同,直接返回
       // 若本机为小端,转换成大端再返回
       return checkCPUendian() ? h : BigLittleSwap32(h);
}
// 模拟ntohl函数,网络字节序转本机字节序
unsigned long int NtoHl(unsigned long int n)
{
       // 若本机为大端,与网络字节序同,直接返回
       // 若本机为小端,网络数据转换成小端再返回
       return checkCPUendian() ? n : BigLittleSwap32(n);
}
// 模拟htons函数,本机字节序转网络字节序
unsigned short int HtoNs(unsigned short int h)
{
       // 若本机为大端,与网络字节序同,直接返回
       // 若本机为小端,转换成大端再返回
       return checkCPUendian() ? h : BigLittleSwap16(h);
}
// 模拟ntohs函数,网络字节序转本机字节序
unsigned short int NtoHs(unsigned short int n)
{
       // 若本机为大端,与网络字节序同,直接返回
       // 若本机为小端,网络数据转换成小端再返回
       return checkCPUendian() ? n : BigLittleSwap16(n);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒听雪落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值