神奇的C语言
当然下面列出来的几点都是C的基础用法,只不过是这些用法可能平时不会被注意。所以很多东西第一次看到的时候,可能会觉得很怪异,但是细细想想就能很好的理解,也就能更好的清楚C语言的一些特性。但是在具体的编码过程当中,我还是希望都能老老实实规规矩矩的。因为程序员不需要太多棱角,把代码写得规范整洁比耍小聪明要重要得多。下面我列举了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语言的更多相关文章
- 对《神奇的C语言》文中例子 5 代码的分析讨论
在春节前,我曾经参与在<神奇的C语言>一文中的例子(5)的讨论,但限于评论内容的有限,现在本文再次对这个问题单独讨论.(此问题原貌,详见<神奇的C语言>,这里我将原文中的代码稍 ...
- 神奇的GO语言:空接口(interface)
对于go语言来说,设计最精妙的应该是interface了,直白点说interface是一组method的组合.至于更加详细的描述,本文不做介绍,今天谈谈空接口. 空interface(interfac ...
- 小C的故事(快速学C语言,,,极速版!)
前几天这篇博客写了太多废话! 删啦~~. 本篇博客只是为chd A协的全嫩小鲜肉入门C语言的预科, 如果你在此处学习C语言, 不幸走火入魔, 小弱概不负责. //请直接随便找个C语言编译器,抄一下下面 ...
- 为什么选择Go语言 GO语言都能做什么产品
Go语言,又称Golang,是Google开发的一款静态强类型.编译型.并发型,并具有垃圾回收机制的编程语言,它的运行速度非常之快,同时还有如下特性:具有一流的标准库.无继承关系.支持多核:同时它还有 ...
- Unity手游之路<十三>手游代码更新策略探讨
http://blog.csdn.net/janeky/article/details/25923151 这几个月公司项目非常忙,加上家里事情也多,所以blog更新一直搁置了.最近在项目开发上线过程中 ...
- python装饰器--@property
@property 考察 Student 类: class Student(object): def __init__(self, name, score): self.name = name sel ...
- ESLint 检查代码质量
利用 ESLint 检查代码质量 其实很早的时候就想尝试 ESLint 了,但是很多次都是玩了一下就觉得这东西巨复杂,一执行检查就是满屏的error,简直是不堪入目,遂放弃.直到某天终于下定决心深入看 ...
- [转载]--用Python 自动安装软件
脚本使用了 Python 2.3 + Com 对象,所以你的系统必须安装Python2.3或更高版本同时必须安装 Mark Hammond's Win32all 模块 (特别感谢Mark Hamm ...
- 关于JavaScript的框架和库
0----无所不能的JavaScript: 说到javascript,最先想到的是用于网页交互的脚本语言,这是最早netscope公司开发的基于浏览器内核的语言:但是最近几年一位大牛一chorme内核 ...
随机推荐
- MySql指令集
http://blog.csdn.net/cl05300629/article/details/9464007
- Linux摄像头驱动学习之:(六)UVC-基本框架代码分析
仿照内核的自带UVC(usb video class)驱动程序写的一版简化驱动,仅供学习,实际项目开发中应该尽量使用内核自带的驱动,除非内核自带的驱动不支持此款硬件才需要自己写驱动. 下面就直接上代码 ...
- poj3259 spfa
spfa判断是否存在负环,path双向,wormhole单向
- php大力力 [044节] PHP的POST语句一定要大写!!if(!empty($_POST['id'])) {
早上花了几个小时,寻找错误!!! 不应该这样写 if(!empty($_Post['id'])) { 应该这样写 if(!empty($_POST['id'])) { 万万不能小谢!
- 观看github前100开源项目的读后感
文章来自:http://www.oschina.net/news/61416/github-top-100-objective-c-projects?from=20150412 ReactiveCoc ...
- html table动态合并单元格 js方法
<script> $(document).ready(function(){ function mc(tableId, startRow, endRow, col) { var tb = ...
- [转]使用 C 编写 Lua 模块
Lua 作为一种小巧的语言,一般都是嵌入到 C/C++ 中作为扩展语言,但是也可以作为独立的脚本语言使用,并且可以使用 C/C++ 编写扩展模块.在参考资料 [1] 中有怎样用 C/C++ 编写模块的 ...
- iOS-UILabel自适应高、宽
UILabel自适应高 UILabel自适应宽
- BNUOJ 13105 nim博弈
ncredible Chess Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on LightOJ. Ori ...
- Android列出所有应用,点击可运行~
这个东西就比较容易了. MainActivity.class import android.app.Activity; import android.content.Context; import a ...