C语言结构体里的成员数组和指针

C语言结构体里的成员数组和指针

单看这文章的标题,你可能会觉得好像没什么意思。你先别下这个结论,相信这篇文章会对你理解C语言有帮助。这篇文章产生的背景是在微博上,看到@Laruence同学出了一个关于C语言的题,微博链接。微博截图如下。我觉得好多人对这段代码的理解还不够深入,所以写下了这篇文章。

zero_array

为了方便你把代码copy过去编译和调试,我把代码列在下面:

#include <stdio.h>
struct str{
    int len;
    char s[0];
};

struct foo {
    struct str *a;
};

int main(int argc, char** argv) {
    struct foo f={0};
    if (f.a->s) {
        printf( f.a->s);
    }
    return 0;
}

你编译一下上面的代码,在VC++和GCC下都会在14行的printf处crash掉你的程序。@Laruence 说这个是个经典的坑,我觉得这怎么会是经典的坑呢?上面这代码,你一定会问,为什么if语句判断的不是f.a?而是f.a里面的数组?写这样代码的人脑子里在想什么?还是用这样的代码来玩票?不管怎么样,看过原微博的回复,我个人觉得大家主要还是对C语言理解不深,如果这算坑的话,那么全都是坑。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (111 人打了分,平均分: 4.63 )
Loading...
无插件Vim编程技巧

无插件Vim编程技巧

相信大家看过《简明Vim教程》也玩了《Vim大冒险》的游戏了,相信大家对Vim都有一个好的入门了。我在这里把我日常用Vim编程的一些技巧列出来给大家看看,希望对大家有用,另外,也是一个抛砖引玉的过程,也希望大家把你们的技巧跟贴一下,我会更新到这篇文章中。另外,这篇文章里的这些技巧全都是vim原生态的,不需要你安装什么插件。我的Vim的版本是7.2

浏览代码

首先,我们先从浏览代码开始。有时候,我们需要看多个文件,所以,传统的做法是,我们开多个tty终端,每个tty里用Vim打开一个文件,然后来回切换。这很没有什么效率。我们希望在一个Vim里打开多个文件,甚至浏览程序目录。

浏览目录的命令很简单:(你也可以直接vim一个目录)

:E

注意,是大写。于是,你会看到下面这样的界面:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (45 人打了分,平均分: 4.22 )
Loading...
Python修饰器的函数式编程

Python修饰器的函数式编程

Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西。虽然好像,他们要干的事都很相似——都是想要对一个已有的模块做一些“修饰工作”,所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去。但是OO的Decorator简直就是一场恶梦,不信你就去看看wikipedia上的词条(Decorator Pattern)里的UML图和那些代码,这就是我在《 从面向对象的设计模式看软件设计》“餐后甜点”一节中说的,OO鼓励了——“厚重地胶合和复杂层次”,也是《 如此理解面向对象编程》中所说的“OO的狂热者们非常害怕处理数据”,Decorator Pattern搞出来的代码简直就是OO的反面教程。

Python 的 Decorator在使用上和Java/C#的Annotation很相似,就是在方法名前面加一个@XXX注解来为这个方法装饰一些东西。但是,Java/C#的Annotation也很让人望而却步,太TMD的复杂了,你要玩它,你需要了解一堆Annotation的类库文档,让人感觉就是在学另外一门语言。

而Python使用了一种相对于Decorator Pattern和Annotation来说非常优雅的方法,这种方法不需要你去掌握什么复杂的OO模型或是Annotation的各种类库规定,完全就是语言层面的玩法:一种函数式编程的技巧。如果你看过本站的《函数式编程》,你一定会为函数式编程的那种“描述你想干什么,而不是描述你要怎么去实现”的编程方式感到畅快。(如果你不了解函数式编程,那在读本文之前,还请你移步去看看《函数式编程》) 好了,我们先来点感性认识,看一个Python修饰器的Hello World的代码。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (41 人打了分,平均分: 4.22 )
Loading...
一个浮点数跨平台产生的问题

一个浮点数跨平台产生的问题

感谢网友唐磊(微博@唐磊_name)投稿,本文原文在唐磊的博客上(原文地址),原文分析还不够好,而且可能对人有误导,所以,我对原文做了很多修改,并加了Linux下的内容。浮点数是一个很复杂的事情,希望这篇文章有助于大家了解浮点数与其相关的C/C++的编译选项。(注:我没有Windows 32位以及C#的环境,所以,对于Windows 32位的程序和C#的程序没有验证过)

背景就简单点儿说,最近一个项目C#编写,涉及浮点运算,来龙去脉省去,直接看如下代码。

float p3x = 80838.0f;
float p2y = -2499.0f;
double v321 = p3x * p2y;
Console.WriteLine(v321);

很简单吧,马上笔算下结果为-202014162,没问题,难道C#没有产生这样的结果?不可能吧,开启Visual Studio,copy代码试试,果然结果是-202014162。就这样完了么?显然没有!你把编译时的选项从AnyCPU改成x64试试~(服务器环境正是64位滴哦!!)结果居然边成了-202014160,对没错,就是-202014160。有点不相信,再跑两遍,仍然是-202014160。呃,想通了,因为浮点运算的误差,-202014160这个结果是合理的。

为什么合理呢?很正常,因为上面的p3x和p2y是两个float类型,虽然v321是double,但也是两个float类型计算完后再转成double的,float的精度本来也只有7位,所以,对于这个上亿的数,自然没有办法保证精度

但是为什么修改CPU的type会有不同的效果?嗯,我们再试试C/C++。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (20 人打了分,平均分: 3.50 )
Loading...
Java中的CopyOnWrite容器

Java中的CopyOnWrite容器

感谢 清英 同学的投稿

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。

什么是CopyOnWrite容器

CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (32 人打了分,平均分: 3.63 )
Loading...
如何用最有创造力的方式输出42

如何用最有创造力的方式输出42

酷壳似乎好长时间没有像《编程真难啊》或是《老手是这样教新手编程的》或是像《如何写出无法维护的代码》这样“严肃正经”的文章了,所以,赶在大家还没有向我扔臭鸡蛋前奉献一篇。这篇文章来自CodeGolf.StackExchange上的《Most creative way to display 42》—— 请以最有创造力的方式输出42。于是出现了下面的这些答案(注:精彩的总是留在最后面)

人生和宇宙终级问题的答案:42

这里,需要介绍一下为什么要输出42。这时因为42是我们人生,世界乃至整个宇宙的终级答案。这要从《银河系漫游指南》(英文名:The Hitchhiker’s Guide to the Galaxy)说起。这本书是著名英国科幻小说作家Douglas  Adams所著5本银河系漫游指南系列科幻喜剧系列小说中的第一本,改编自他本人为英国广播公司第四电台(BBC Radio 4)所写的广播剧剧本。该书1979年10月12日首次由麦克米伦出版公司(Pan Books)出版,次周成为英国图书销量榜冠军,前3个月内销售超过25万本。截至2005年,这本小说已被翻译成超过30种语言在全世界发行,并且被改编为电视剧、电影、舞台剧等多种艺术形式的作品。

这本小说中小说中充满尖锐的讽刺和隐喻,被西方科幻爱好者奉为“科幻圣经”。其中有两个关键词,一个是Don’t Panic,一个是42影响力很大,而其中关于42的故事简介是这样的:

百万年前,老鼠其实是一种超智慧生物,它们建造了一部超级电脑深思Deep Thought,它们问超级电脑,生命、宇宙以及任何事情的终极答案(Answer to Life, the Universe, and Everything)什么,经过了750万年的计算,深思告诉老鼠的后人答案是42,深思解释它只能计算出答案是什么,但答案的原因必须由另一部更高智能的电脑才能解释,而该部电脑就是地球。经过了800万年,就在结果要出来的五分钟前,地球却因为挡在预定兴建的星际间高速公路的路线,被Vogons给毁灭,电脑没有给出最后的结果。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (32 人打了分,平均分: 3.94 )
Loading...
由苹果的低级Bug想到的

由苹果的低级Bug想到的

2014年2月22日,在这个“这么二”的日子里,苹果公司推送了 iOS 7.0.6(版本号11B651)修复了 SSL 连接验证的一个 bug。官方网页在这里:http://support.apple.com/kb/HT6147,网页中如下描述:

Impact: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS

Description: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps.

也就是说,这个bug会引起中间人攻击,bug的描述中说,这个问题是因为miss了对连接认证的合法性检查的步骤。

这里多说一句,一旦网上发生任何的和SSL/TL相关的bug或安全问题,不管是做为用户,还是做为程序员的你,你一定要高度重视起来。因为这个网络通信的加密协议被广泛的应用在很多很多最最需要安全的地方,如果SSL/TLS有问题的话,意味着这个世界的计算机安全体系的崩溃。

Bug的代码原因

Adam Langley的《Apple’s SSL/TLS bug 》的博文暴出了这个bug的细节。(在苹果的开源网站上,通过查看苹果的和SSL/TLS有关的代码变更,我们可以在文件sslKeyExchange.c中找到下面的代码)

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (58 人打了分,平均分: 4.47 )
Loading...
可视化编程

可视化编程

本文来自《Visual Programming Languages – Snapshots》,作者Eric Hosick收集了一堆关于可视化编程的工具,好多我都听都没听说过,我一股脑的全转过来,给大家看看,算是开开眼界了。本文也是参考了Wikipedia的 Visual Programming Language 词条。

另外,在原文有很多评论,其中也有很多正文没有提到的,你可以前去围观一下。

SketchPad

Maybe the first. 1963.

图片来源, Wikipedia官方网站

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (21 人打了分,平均分: 3.86 )
Loading...
从“黑掉Github”学Web安全开发

从“黑掉Github”学Web安全开发

Egor Homakov(Twitter: @homakov 个人网站: EgorHomakov.com)是一个Web安全的布道士,他这两天把github给黑了,并给github报了5个安全方面的bug,他在他的这篇blog——《How I hacked Github again》(墙)说明了这5个安全bug以及他把github黑掉的思路。Egor的这篇文章讲得比较简单,很多地方一笔带过,所以,我在这里用我的语言给大家阐述一下黑掉Github的思路以及原文中所提到的那5个bug。希望这篇文章能让从事Web开发的同学们警惕。关于Web开发中的安全事项,大家可以看看这篇文章《Web开发中的你需要了解的东西

OAuth简介

首先,这个故事要从Github OAuth讲起。所以,我们需要先知道什么是OAuth。所谓OAuth就是说,第三方的应用可以通过你的授权而不用知道你的帐号密码能够访问你在某网站的你自己的数据或功能。像Google, Facebook, Twitter等网站都提供了OAuth服务,提供OAuth服务的网站一般都有很多开放的API,第三方应用会调用这些API来开发他们的应用以让用户拥有更多的功能,但是,当用户在使用这些第三方应用的时候,这些第三方的应用会来访问用户的帐户内的功能和数据,所以,当第三应用要干这些事的时候,我们不能让第三方应用弹出一个对话框来问用户要他的帐号密码,不然第三方的应用就把用户的密码给获取了,所以,OAuth协议会跳转到一个页面,让用户授权给这个第三方应用以某些权限,然后,这个权限授权的记录保存在Google/Facebook/Twitter上,并向第三方应用返回一个授权token,于是第三方的应用通过这个token来操作某用户帐号的功能和数据时,就畅通无阻了。下图简单地说明了Twitter的OAuth的授权过程。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (56 人打了分,平均分: 4.02 )
Loading...
一个“蝇量级” C 语言协程库

一个“蝇量级” C 语言协程库

(感谢网友 @我的上铺叫路遥 投稿)

协程(coroutine)顾名思义就是“协作的例程”(co-operative routines)。跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程技巧。实际上协程的概念比线程还要早,按照 Knuth 的说法“子例程是协程的特例”,一个子例程就是一次子函数调用,那么实际上协程就是类函数一样的程序组件,你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。只不过子例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,又可以从上一个返回点继续执行,也就是说协程之间可以通过 yield 方式转移执行权,对称(symmetric)、平级地调用对方,而不是像例程那样上下级调用关系。当然 Knuth 的“特例”指的是协程也可以模拟例程那样实现上下级调用关系,这就叫非对称协程(asymmetric coroutines)。

基于事件驱动模型

我们举一个例子来看看一种对称协程调用场景,大家最熟悉的“生产者-消费者”事件驱动模型,一个协程负责生产产品并将它们加入队列,另一个负责从队列中取出产品并使用它。为了提高效率,你想一次增加或删除多个产品。伪代码可以是这样的:

# producer coroutine
loop
while queue is not full
  create some new items
  add the items to queue
yield to consumer

# consumer coroutine
loop
while queue is not empty
  remove some items from queue
  use the items
yield to producer

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (40 人打了分,平均分: 4.18 )
Loading...