基于c语言知识点的补遗介绍_C 语言

使用C很长时间,但是很难说对c的各个点都十分的透彻。虽然c不像c++那样复杂,但是还有很多叽里旮旯儿:并不是他们有多难,而是在于他们平时用的不多,或者和人的第一直觉相悖,再或者初学时经验有限理解不深根本没有记住。
下面的这些东西可能来自《c专家编程》或者网络。最近发现基础的经典的书籍常读常新,原因可能有两个:
1、随着自己经验的增长,你的认识可能会不一样,思维的方式也会有所变化,而得到的东西自然会是新的东西。
2、早些时候经验有限,有些点可能根本就没有完全理解。现在你可以理解的更深刻。
这方面的书籍再比如《代码大全》,前几天翻了一下,又有不同的认识。
进入正题:
1、有符号和无符号的比较:
printf("%d\n", sizeof('A')):打印的值是4(或者是int的长度)而不是1。因为c有类型提升,它会首先把'A'提升为int类型,然后在传给sizeof。表达式中的参数会提升为int或者double,然后在进行运算,之后再进行裁剪,获得指定类型的值。
if (-1 <= sizeof(int)):sizeof的返回值是unsigned int,-1会被类型转换为unsignedint,然后在进行比较。。
这里涉及到的是类型提升,隐式类型转换。它会在表达式中发生,也会在函数入参中发生。
2、枚举在内存中的大小:占四个字节。
3、局部变量也是字节对齐的:
        E_T g;
        E_T f;
        E_T e = false;
        char c1;
        char c2;
        int i1;
        char c3;
        int i2;
printf("%p, %p, %p, %p, %p, %p, %p, %p\n", &g, &f, &e, &c1, &c2, &i1, &c3, &i2);

--表示是补齐的位。
4、宏定义中的#和##:#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。
5、浮点数不可以用等于比较。
6、void foobar2() 表示函数入参个数有多个,不确定。如果表示没有产生,应该是:void foobar2(void)
7、全局变量会被初始化为0,但是,栈中的局部变量不会被初始化。
8、inline函数和宏:内联函数是真正的函数,但是它是在编译期的优化。
9、    int a[5];    printf("%x\n", a);    printf("%x\n", a+1);    printf("%x\n", &a);    printf("%x\n", &a+1);
最后一个,&a+1,&a表示数组,所以,应该是增加数组大小:4*5个字节。
10、10U表示一个无符号类型的数字10.
11、移位运算的优先级比较低,低于四则运算。
12、左移n位,相当于乘与2的n次方。右移相当于处于2的n次方。
13、指针和数组:
1)、void fun(char buf[100])
{
printf("%d, \n", sizeof(buf));
}
打印的值是4,而不是100。
2)、在一个文件中char p[10] = "";
在另外一个文件中声明:extern char *p;
然后,在声明的文件中sizeof(p),答案是4。也就是,sizeof计算的是声明的类型。
3)对于编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。
4)所有作为函数参数的数组名编译器都会转换为指针,在其他所有的情况下,数组的声明就是数组,指针的什么就是指针。
数组和指针相同情况的规则:
1、表达式中的数组名(与声明不同)被编译器当作一个指向该数组的第一个元素的指针。
2、下标总是与指针的偏移量相同。
3、在函数的声明中,数组名被编译器当作指向该数组第一个元素的指针。这个操作时编译器完成的。原因是出于效率的考虑。因为这样就是引用传递而非值传递。值 传递需要拷贝。这也可以看的出sizeof是在汇编中操作的。
arry[-1]的行为是未定义的。
总结:
1)a[i]这样的形式对a进行访问,总是被编译器改写为像*(a+i)的形式。
2)指针始终是指针,你不可以把它改写成数组,但是可以通过数组的形式访问。
3)数组作为函数的参数,会被编译器改写成指针。
4)指针和数组的什么必须配对。
14、声明与定义:声明可以由多个,定义只有一个。定义是特殊的声明,它为对象分配了内存。而声明时普通的声明,描述其他地方创建的对象。
声明的优先级规则:
a:从他的名字开始按照优先次序依次读取:
b:优先级的高低:
1、声明中被括号括起来的那部分。
2、后缀操作符:
括号()表示是一个函数;
方括号[]表示是一个数组;
3、前缀操作符:*表示指向什么的指针;
4、const紧跟变量则修饰变量不可修改,紧跟类型则指向的东西不可修改。
15、多维数组:
a[2][3]:a是一个数组,有两个元素。每个元素又是一个数组,有三个元素。
内存布局:a[0][0],a[0][1],a[0][2],a[1][0]...地址一直变大。
多维数组,数组的数组作为函数的形参,会被转化为数组指针,数组的指针,也是行指针。本质上也是指针。
16、结构体默认的字节对齐一般满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

时间: 2024-10-25 10:34:32

基于c语言知识点的补遗介绍_C 语言的相关文章

C语言 位段的详细介绍_C 语言

C语言中的位段       位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间.含有位段的结构体(联合体)称为位段结构.采用位段结构既能够节省空间,又方便于操作.      位段的定义格式为:      type  [var]: digits     其中type只能为int,unsigned int,signed int三种类型(int型能不能表示负数视编译器而定,比如VC中int就默认是signed int,能够表示负数).位段名称var是可选参数,即可以省

C语言 条件判断详细介绍_C 语言

C 判断 判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的). C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false. 下面是大多数编程语言中典型的判断结构的一般形式: 判断语句 C 语言提供了以下类型的判断语句.点击链接查看每个语句的细节.   语句 描述 if 语句 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成. if...else 语句 一个 if 语句 后可跟一个可选的 el

C++开发:为什么多线程读写shared_ptr要加锁的详细介绍_C 语言

我在<Linux 多线程服务端编程:使用 muduo C++ 网络库>第 1.9 节"再论 shared_ptr 的线程安全"中写道: (shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化.根据文档(http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#ThreadSafety), shared_ptr 的线程

linux下基于C语言的信号编程实例_C 语言

本文实例讲述了linux下基于C语言的信号编程方法.分享给大家供大家参考.具体如下: #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> void sig_handler(int sig_no, siginfo_t *info, void *ctext){ printf("receive si

基于C++实现的线程休眠代码_C 语言

本文实例讲述了基于C++实现的线程休眠代码,分享给大家供大家参考.具体方法如下: linux平台示例如下: /* File : thread1.c Author : Mike E-Mail : Mike_Zhang@live.com */ #include <stdio.h> #include <pthread.h> #include <time.h> void m_threadSleep(int sec,int nsec) { struct timespec slee

C/C++产生随机数函数简单介绍_C 语言

计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子.(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了.)  我们知道rand()函数可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数

C语言 数据类型详细介绍_C 语言

C 数据类型 在 C 语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统.变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式. C 中的类型可分为以下几种: 序号 类型与描述 1 基本类型: 它们是算术类型,包括两种类型:整数类型和浮点类型. 2 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量. 3 void 类型: 类型说明符 void 表明没有可用的值. 4 派生类型: 它们包括:指针类型.数组类型.结构类型.共用体类型和函数类型.

C++实现基于控制台界面的吃豆子游戏_C 语言

本文实例讲述了C++实现基于控制台界面的吃豆子游戏.分享给大家供大家参考.具体分析如下: 程序运行界面如下所示: ESC键可退出游戏. main.cpp源文件如下: #include "lib.h" #pragma once extern int level; int main() { FOOD food; WALL wall; BODY CurPos; HALL hall; int iExit = 0; while(1) { if(iExit) break; Init(&fo

C语言 栈的表示和实现详细介绍_C 语言

C语言 栈的表示和实现详细介绍 定义:栈是限定仅在表尾进行插入和删除操作的线性表. 栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操作的特殊线性表.允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom):栈底固定,而栈顶浮动: