当然下面列出来的几点都是C的基础用法,只不过是这些用法可能平时不会被注意。所以很多东西第一次看到的时候,可能会觉得很怪异,但是细细想想就能很好的理解,也就能更好的清楚C语言的一些特性。但是在具体的编码过程当中,我还是希望都能老老实实规规矩矩的。因为程序员不需要太多棱角,把代码写得规范整洁比耍小聪明要重要得多。下面我列举了5个例子说明一些问题,如果你是老手看到这些就一笑而过吧,如果是新手,我相信还是会得到一些启发的。

1. #和##在宏中的作用,以及带参宏,参数的传递问题。

2. 结构体中域的偏移位置的计算问题。

3. 结构体的定义以及初始化的用法。

4. 数组和指针在运算中的等价关系。

5. 数组在栈中的“变异”。

1. 例子:

    #include <stdio.h>

    #define _mir(a) #a
int main()
{
char * s = _mir(
struct _st{
int a;
int b;
int c;
};
);
printf( "%s\n", s );
return 0;
}

输出:

    struct _st{ int a; int b; int c; };

说明:

A) 预编译中#是将右边的参数转成一个字符串,##是将左右两边的参数连接成一个字符串。例子是#的用法。
B) 宏当中的参数其实是以逗号(,)分隔的,其他的字符其实都被看成同一个参数,但是换行和空白其实被处理过了,使参数在同一个行中。有兴趣的自己多做些测试吧,这个用法可以用于要写包含特殊字符的字符串,免得要写很多的转义字符(\),但是中间不能有逗号,呵呵~

2. 例子:

    #include <stdio.h>

    struct _st{
int a;
int b;
int c;
}; void main()
{
printf( "%d\n", &((struct _st*)0)->b );
}

输出:

    4

说明:

A) &((struct _st*)0)->b 的作用是输出_st结构体中b的偏移。为什么用0当成指针呢,其实很好理解:如果一个_st结构体的地址是0,那么b的地址其实就是b在结构体中的偏移。
B) 其实按理,如果先做((struct _st*)0)->b运算,那么程序肯定异常,所以编译器还是做了优化的,具体编译器怎么做的,我也没深究。

3. 例子:

    #include <stdio.h>

    struct _st{
int a : 1;
int b : 1;
int c : 1;
}s = {
.c = 1,
.b = 0,
.a = 0
}; void main()
{
printf( "%d %d %d %d\n", sizeof(s), s.a, s.b, s.c );
}

输出:

    4 0 0 -1

说明:

A) 在结构体的初始化时,可以指定域进行初始化,如例子中的.c = 1,顺序可以颠倒,这样做的好处就是可读性较强,对于大结构的初始化,在阅读时很方便。缺点就是低版本的编译器可能不支持。
B) 在结构体的声明中,可以指定域的大小,如例子中的int a : 1; 说明a只暂用一个bit,充分展示了C对二进制处理反面的亲和力。
C) 为什么s.c输出是-1,而不是1,其实很简单,因为0xFFFFFFFF表示的是-1,那么一个1bit大小的变量,所有位上面都是1,那么它也表示-1。所以编码的过程中,有符号和无符号混用其实是很危险的一件事情。
4. 例子:

    #include <stdio.h>
void main()
{
int i;
char a[10]="hello"; 0[a] = 'x';
printf( "%s\n", a ); for( i=0; i<10; i++ )
printf( "%c", (rand()%10)["0123456789"] );
printf( "\n" ); }

输出:

    xello
1740948824

说明:

A) 0[a] = 'x';是什么玩意儿?如果写成a[0]='x';其实你就明白是什么意思了,但是说白了,a[0]和0[a]在编译器看来是一样的。因为数组在做[]运行时,其实是做指针的加法运行:a[0]等价于*(a+0)。所以0[a]也就等价于*(0+a)是完全正确的。
B) 循环中功能是输出一个10位的随机数。其实也等价于"0123456789"[rand()%10]。这里"0123456789"的类型是char*,所以指针也支持[]运算,因为[]运算其实就是加法运算。

5. 例子:

    #include <stdio.h>

    void func( char a[10] )
{
printf( "%d %d\n", &a, &a[0] );
} void main()
{
char a[10];
printf( "%d %d\n", &a, &a[0] );
func( a );
}

输出:

    1638208 1638208
1638192 1638208

说明:

A) 为什么两行的结果会不一样?在一般情况下,按我的理解,一个数组a,&a和&a[0]的值是一样的。但是当a在形参当中时就不一样了。例子中,func函数中的a,其实a变量是在func函数的栈当中,在func内部,a其实已经被转化成char *a,所以&a是表示指针变量a在栈中的地址,而&a[0]表示的是指针指向的内存空间的第一个元素的地址,其实也就是调用者传入的数组的第一个元素的地址。不知道我说明白了没有!!
B) 这个可能比较难理解,关键是明白一点,在数组作为形参时,是被转换成指针看待的。

神奇的C语言的更多相关文章

  1. 对《神奇的C语言》文中例子 5 代码的分析讨论

    在春节前,我曾经参与在<神奇的C语言>一文中的例子(5)的讨论,但限于评论内容的有限,现在本文再次对这个问题单独讨论.(此问题原貌,详见<神奇的C语言>,这里我将原文中的代码稍 ...

  2. 神奇的GO语言:空接口(interface)

    对于go语言来说,设计最精妙的应该是interface了,直白点说interface是一组method的组合.至于更加详细的描述,本文不做介绍,今天谈谈空接口. 空interface(interfac ...

  3. 小C的故事(快速学C语言,,,极速版!)

    前几天这篇博客写了太多废话! 删啦~~. 本篇博客只是为chd A协的全嫩小鲜肉入门C语言的预科, 如果你在此处学习C语言, 不幸走火入魔, 小弱概不负责. //请直接随便找个C语言编译器,抄一下下面 ...

  4. 为什么选择Go语言 GO语言都能做什么产品

    Go语言,又称Golang,是Google开发的一款静态强类型.编译型.并发型,并具有垃圾回收机制的编程语言,它的运行速度非常之快,同时还有如下特性:具有一流的标准库.无继承关系.支持多核:同时它还有 ...

  5. Unity手游之路<十三>手游代码更新策略探讨

    http://blog.csdn.net/janeky/article/details/25923151 这几个月公司项目非常忙,加上家里事情也多,所以blog更新一直搁置了.最近在项目开发上线过程中 ...

  6. python装饰器--@property

    @property 考察 Student 类: class Student(object): def __init__(self, name, score): self.name = name sel ...

  7. ESLint 检查代码质量

    利用 ESLint 检查代码质量 其实很早的时候就想尝试 ESLint 了,但是很多次都是玩了一下就觉得这东西巨复杂,一执行检查就是满屏的error,简直是不堪入目,遂放弃.直到某天终于下定决心深入看 ...

  8. [转载]--用Python 自动安装软件

    脚本使用了  Python 2.3 + Com 对象,所以你的系统必须安装Python2.3或更高版本同时必须安装  Mark Hammond's Win32all 模块 (特别感谢Mark Hamm ...

  9. 关于JavaScript的框架和库

    0----无所不能的JavaScript: 说到javascript,最先想到的是用于网页交互的脚本语言,这是最早netscope公司开发的基于浏览器内核的语言:但是最近几年一位大牛一chorme内核 ...

随机推荐

  1. Yii2 主从 数据库

    配置方法 参考资料:http://www.linuxidc.com/Linux/2015-07/120134.htm 读写分离(Read/Write Splitting). 1.原理:让主数据库(ma ...

  2. 用python定时文章发布wordpress

    用python定时文章发布wordpress: 流程: 采集 - 筛选文章 - wordpress文章发布. wordpress文章发布代码:python利用模块xmlrpclib发布文章非常便捷,省 ...

  3. Adaboost 2

    本文不定期更新.原创文章,转载请注明出处,谢谢. Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类 ...

  4. Pig与Hive的区别

    Language 在Hive中可以执行  插入/删除 等操作,但是Pig中我没有发现有可以 插入 数据的方法,请允许我暂且认为这是最大的不同点吧. Schemas Hive中至少还有一个“表”的概念, ...

  5. Data storage on the batch layer

    4.1 Storage requirements for the master dataset To determine the requirements for data storage, you ...

  6. 三部曲二(基本算法、动态规划、搜索)-1006-The Same Game

    The Same Game Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4585   Accepted: 1699 Des ...

  7. flask开发遇到 Must provide secret_key to use csrf解决办法

    开发flask的时候,遇到了 Must provide secret_key to use csrf错误提醒.原来是没有设置secret_key .在代码中加上 app.config['SECRET_ ...

  8. Node.js高级编程读书笔记 - 4 构建Web应用程序

    Outline 5 构建Web应用程序 5.1 构建和使用HTTP中间件 5.2 用Express.js创建Web应用程序 5.3 使用Socket.IO创建通用的实时Web应用程序 5 构建Web应 ...

  9. jquery 之ajax获取数据

    $.ajax({    url: "http://www.hzhuti.com",    //请求的url地址    dataType: "json",   / ...

  10. TortoiseGit 添加ssh key

    TortoiseGit 使用扩展名为ppk的密钥,而不是ssh-keygen生成的rsa密钥.使用命令ssh-keygen -C "邮箱地址" -t rsa产生的密钥在Tortoi ...