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

 更新时间:2013年05月23日 15:48:18   作者:  
本篇文章是对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)。

相关文章

  • OpenCV实现轮廓的发现

    OpenCV实现轮廓的发现

    这篇文章主要为大家详细介绍了OpenCV如何实现轮廓的发现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 利用Qt制作简单的日期选择界面

    利用Qt制作简单的日期选择界面

    Qt自带的日期选择控件过于丑陋与难用,所以但凡有点小想法的人都会做一个全新的日历。这篇文章就来利用Qt制作一个简单的日期选择界面,感兴趣的可以了解一下
    2023-03-03
  • 基于WTL中使用双缓冲避免闪烁的解决方法

    基于WTL中使用双缓冲避免闪烁的解决方法

    本篇文章是对WTL中使用双缓冲避免闪烁的解决方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++实现和电脑对战三子棋实例

    C++实现和电脑对战三子棋实例

    大家好,本篇文章主要讲的是C++实现和电脑对战三子棋实例,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • C语言设计前中后队列实例代码

    C语言设计前中后队列实例代码

    队列最主要的作用就是用来管理数据流的,防止数据因为传输频率过快得不到及时处理而丢失,下面这篇文章主要给大家介绍了关于C语言设计前中后队列的相关资料,需要的朋友可以参考下
    2021-12-12
  • 实例代码分析c++动态分配

    实例代码分析c++动态分配

    这篇文章主要介绍了c++动态分配的的相关资料,文中代码简单易懂,方便大家更好的学习参考,感兴趣的朋友可以了解下
    2020-06-06
  • C语言的sleep、usleep、nanosleep等休眠函数的使用

    C语言的sleep、usleep、nanosleep等休眠函数的使用

    本文主要介绍了C语言的sleep、usleep、nanosleep等休眠函数的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 成员函数的重载、覆盖与隐藏详细解析

    成员函数的重载、覆盖与隐藏详细解析

    成员函数的重载、覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚概念,否则错误将防不胜防
    2013-10-10
  • MFC修改编辑框光标显示位置方法详解

    MFC修改编辑框光标显示位置方法详解

    这篇文章主要介绍了在MFC中利用CComboBox控件修改编辑框光标显示位置的两种解决方法,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-02-02
  • C++实现四则混合运算计算器

    C++实现四则混合运算计算器

    这篇文章主要为大家详细介绍了C++实现四则混合运算计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11

最新评论