c语言几个,几个C语言知识点

c语言几个,几个C语言知识点
文章图片

8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
重新整理以前的笔记,基本来自《C语言深度解剖》。
原码/反码/补码
原码:原码就是这个数本身的二进制形式,其中最高位为符号位。
补码:在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。
反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
求补码的方法:整数或零,则补码等于原码,负数则补码等于除符号位外,各位取反加一
求反码的方法:正数,反码与原码相同,负数,对其原码逐位取反,但符号位除外,符号位还是一
在计算机系统中,数值一律用补码来表示。
问题1:
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
以上代码输出为255
问题2:
char a = -300,求 int a
300的原码:1 0010 1100
取反:1101 0011
加一:1101 0100
300的补码:1101 0100
符号位:1
求原码:101 0100
取反:010 1011
加一:010 1100
求得:-44
问题3:
int i = -20;
unsigned j = 10;
i+j的值为多少?为什么?
问题4:
下面的代码有什么问题?
unsigned i ;
for (i=9; i>=0; i--)
{
printf("%un",i);
}
数据类型基本类型 - 数值类型、字符类型
构造类型 - 数组、结构体、共用体、枚举类型
指针类型
空类型
常用数据类型在32位和64位CPU上的字节数比较:
测试进程:
printf("char[%d], char*[%d], short int[%d], int[%d], unsigned int[%d], float[%d], double[%d], long[%d], long long[%d], unsigned long[%d]n",
sizeof(char),sizeof(char *),
sizeof(short int),sizeof(int),sizeof(unsigned int),
sizeof(float),sizeof(double),
sizeof(long),sizeof(long long),sizeof(unsigned long));
不同CPU类型的输出结果:
x86_64:char[1], char*[8], short int[2], int[4], unsigned int[4], float[4], double[8], long[8], long long[8], unsigned long[8]
i686:
总结:很明显的比较结果,指针和长整形由4个字节升为8个字节
32个关键字
举例:
register - 声明寄存器变量
const - 声明只读变量
volatile - 说明变量在进程执行中可被隐含地改变。这个关键字声明的变量,编译器对访问该变>量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
分析:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。(对Java来说:Java内存模型告诉我们,各个线程会将共享变量从主内存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理。线程在工作内存进行操作后何时会写到主内存中?这个时机对普通变量是没有规定的,而针对volatile修饰的变量给java虚拟机特殊的约定,线程对volatile变量的修改会立刻被其他线程所感知,即不会出现数据脏读的现象,从而保证数据的“可见性”。)
下面是volatile变量的几个例子:并行设备的硬件寄存器(如:状态寄存器)
一个中断服务子进程中会访问到的非自动变量(Non-automatic variables)
多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C进程员和嵌入式系统进程员的最基本的问题。嵌入式系统进程员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
有如下3个问题:一个参数既可以是const还可以是volatile吗?解释为什么。
一个指针可以是volatile 吗?解释为什么。
下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为进程不应该试图去修改它。
是的。尽管这并不很常见。一个例子是当一个中断服务子进程修改一个指向一个buffer的指针时。
这段代码的有个恶作剧。这段代码的目的是用来返指针ptr指向值的平方,但是,由于ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b; a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a; a = *ptr;
return a * a;
}
extern: 说明变量是在其他文档中声明(也可以看作是引用变量)
sizeof: 计算对象所占内存空间大小
函数参数的声明举例:void func(int i,char c)
定义声明最重要的区别:定义创建了对象,并为这个对象分配了内存,声明没有分配内存
编译器在默认的缺省情况下,所有变量都是auto的。
register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整形的长度。而且register变量可能不存在内存中,所以不能用取址运算符“&”来获取register变量的地址。比如说,32位的CPU,最多是4个字节,整形和长整形都是占4个字节的数据类型。
注意:register变量只是对编译器的建议,编译器并不一定会将该变量作为register变量。
static关键字作用修饰变量
静态区是分配静态变量、全局变量空间的;初始化的全局变量放在数据段;局部变量放在栈;未初始化的全局变量放在bss段。
从C进程运行的角度看,内存几大部分:静态存储区、堆区和栈区。
静态存储区:内存在进程编译的时候就已经分配好,这块内存在进程的整个运行期间都存在。它主要存在静态数据、全局数据和常量。
全局区(静态区)(static) —- 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。进程结束后由系统释放。
#include int a = 0; //全局初始化区 char *p1; //全局未初始化区 void main(void)
{
int b; //栈 char s[] = "abc"; //栈 char *p2; //栈 char *p3 = "123456"; //123456 在常量区,p3在栈上 static int c = 0; //全局(静态)初始化区 p1 = (char *)malloc(10); //堆 p2 = (char *)malloc(20); //堆 p1 = "123456"; //123456 在常量区,编译器将p1与p3所指向的“123456 ”优化成同一个地方 }
全局变量、局部变量、静态全局变量、静态局部变量的区别,如下:从作用域看全局变量具有全局域。全局变量只需在一个源文档中定义,就可以作用于所有的源文档。当然,其他不包括全局变量定义的源文档需要用extern关键字再次声明这个全局变量。
静态局部变量具有局部作用域。它只被初始化一次,自从第一次初始化直到进程结束都一直存在。它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
局部变量也只有局部作用域,他是自动对象,他在进程运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用结束后,变量就被撤销,其所占用的内存也被收回。
静态全局变量(其他文档即使使用extern声明也没法使用它)也具有全局作用域,它与全局变量的区别在于如果进程包含多个文档的话,他作用于定义它的文档里,不能作用到其他文档里,即被static关键字修饰过的变量具有文档作用域。这样即使两个不同的源文档都定义了相同的静态全局变量,它们也是不同的变量。
从分配内存空间看
全局变量、静态全局变量、静态全局变量都在静态存储区分配空间,而局部变量在栈分配空间。
把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生命周期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围,因此static这个说明符在不同的地方起的作用是不同的。
注意:
对于静态局部变量的理解:若全局变量仅在单个函数中使用,则可以将这个变量修改为改函数的静态局部变量
由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁,函数下次使用时仍然能用到这个值
直观的例子:
int k,ii = 0;
static int j;
void func1(void)
{
static int i = 0;
i++;
ii++;
printf("i = %dn",i);
printf("ii = %dn",ii);
}
void func2(void)
{
j = 0;
j++;
printf("j = %dn",j);
}
int main()
{
for(k=0; k<10; k++)
{
func1();
func2();
sleep(1);
}
return 0;
}
修饰函数
函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文档(所以又称为内部函数)。
C++里对static赋予了第三个作用(如果成员声明为static,可以在外部直接访问)静态数据成员静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一个内存,供所有对象共用
静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义
静态成员函数静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数
非静态成员函数可以任意地访问静态成员函数和静态数据成员
静态成员函数不能访问非静态成员函数(不包括构造函数)和非静态数据成员
【c语言几个,几个C语言知识点】sizeof关键字

    推荐阅读