当然下面列出来的几点都是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. MyEclipse中Maven的配置

    之前在MyEclipse这个IDE中配置Maven,完成配置后启动Maven时出现-Dmaven.multiModuleProjectDirectory system propery is not s ...

  2. 微信JS-SDK DEMO页面和示例代码

    <?php require_once "jssdk.php"; $jssdk = new JSSDK("yourAppID", "yourApp ...

  3. 排序小结(java版)

    一.归并排序 package org.lxh.demo08.b; class Sort { private int[] a; private int n; Sort(int n) { a=new in ...

  4. 64位Win7系统下vs2010调试无法连接oracle

    64位win7系统的Program Files (x86)路径中有括号,oracle不认识这样的路径,所以就出现不能连接数据库的问题.所以我们可以将vs2010的内部调试web服务器WebDev.We ...

  5. ubuntu频繁掉线 转

    好长好长时间没来百度空间了,最近闲来无事,正好弥补之前的空缺了!跟Ubuntu打交道已有很长一段时间了,期间遇到了很多问题,我把遇到的一些问题及找到的解决方案记录下来,我想这可能会对那些跟我有同样境遇 ...

  6. jQuery遍历Json数组

    var jsonArray=  [{ "name": "张三", "password": "123456"},{ &qu ...

  7. HBase with MapReduce (Summary)

    我们知道,hbase没有像关系型的数据库拥有强大的查询功能和统计功能,本文实现了如何利用mapreduce来统计hbase中单元值出现的个数,并将结果携带目标的表中, (1)mapper的实现 pac ...

  8. 从零开始学习Node.js例子四 多页面实现数学运算 续一(使用connect和express框架)

    1.使用connect框架 .use方法用于绑定中间件到connect服务器,它会配置一系列在接到请求时调用的中间件模块,此例中我们要配置的中间件有favicon logger static rout ...

  9. 看啦这么就别人的博客 我也来写一篇! Object转换其他类型

    package com.sinitek.framework.util; import java.math.BigDecimal;import java.sql.Timestamp;import jav ...

  10. 去除Visual Studio引号中的内容和注释中出现的波浪下划线

    [描述] 使用vs2013,注释或者字符串常量中,经常会出现红色的波浪线,非常烦人. 注意,不是代码错误的那种波浪线,我觉得代码错误智能提示的波浪线还是有必要留着的,这样可以避免过多的编译来发现错误, ...