2010年11月 存档

C语言中的字符串常量

2010年11月30日,星期二

说起字符串常量,学过C语言的人都不陌生。字符串常量的书写方式是一对双引号包围一串字符,如:

"Hello, world"

当一个字符串常量出现于一个表达式中时,表达式所使用的值就是这些字符所储存的地址,而不是这些字符本身。因此,你可以把字符串常量赋值给一个“指向字符的指针”,后者指向这些字符所储存的地址,如:

char *str = "Hello, world";

但是,你不能把字符串常量赋值给一个字符数组,因为字符串常量的直接值是一个指针,而不是这些字符本身。简单的说,字符串常量的值是这些字符在内存中的地址。

现在考虑下面一段代码:

if("Demon")
    printf("true");
else
    printf("false");

你认为会输出什么,true or false?

文件属性中“大小”和“占用空间”的区别

2010年11月29日,星期一

很多人一直在困惑,一个文件或文件夹属性中的“大小(Size)”和“占用空间(Size on disk)”通常不相互匹配。“大小”的值表示文件实际大小的字节数,而“占用空间”的值表文件占用硬盘空间大小的字节数。

这种差异来自文件系统在驱动器上存储的文件的方式。为了减少使用的地址数量,文件系统把一定数量的字节当成簇。根据不同的文件系统,常见的簇大小可以从2KB的到32KB。一个被写入到磁盘的文件需要占用若干个不相连的簇,而无论文件的实际大小。因此,一个1KB的文件,保存在一个簇大小为2KB的文件系统将占用2KB,但保存在一个簇大小为32KB的文件系统,它会占用32KB。也就是说,一个33KB的文件将占用17个2KB的簇(34KB)或2个32KB的簇(64KB)。

基于上述的讨论,你会期望占用空间的大小会比实际大小更大,但是多出的部分不会超过一个簇的大小。在查看一个有很多文件的文件夹时,这种差异可能会更大,因为每个单独文件浪费的空间加起来会体现在文件夹上。

简单地说,就是:

  1. “大小”是文件的实际字节数,而“占用空间”的是在磁盘上占用的字节数。
  2. “占用空间”通常比“大小”要大,但也可以和“大小”一样

公式(JavaScript描述):

//簇大小,一般为4KB
var cluster = 4096;
//文件大小,单位为字节
var size = 4282661;
//占用大小,单位为字节
var size_on_disk = 
Math.ceil(size / cluster) * cluster;
//回显
WScript.Echo(size_on_disk);

参考链接:Difference Between Size vs Size on Disk

TCC,很小很强大

2010年11月28日,星期日

一直喜欢用很小很强大的软件,如uTorrent、EditPlus、WinRAR、UltraISO、VbsEdit等等,TCC也是其中的一员。

说起TCC就不得不提到TC,因为它们的缩写很像。TC是Turbo C的缩写,是Borland公司开发的DOS环境下的C语言集成开发环境,Borland公司的传奇就是从TC开始的。DOS时代已成为过去,Borland传奇也已成为历史,但是国内仍然有很多C语言教材里用TC作为编译器,谭浩强的烂书《C语言程序设计》就是其中的一本。

TCC是Tiny C Compiler的缩写,传说是目前最小的ANSI C语言编译器,支持Windows和Linux平台。Windows下的TCC解压后文件夹仅932KB,连1000KB都不到。Ubuntu系统可以通过apt-get install tcc命令来安装。你可以使用这个不到1000K的编译器编译你的C源码,它支持C的预处理,编译,机器码汇编和链接。编译速度也超过了GCC,而且它支持ISO C99标准,并且还包括了一些内存和数组边界的检查。它甚至还可以编译Linux的内核。

不仅TCC本身很小,而且TCC编译出来的程序也很小。用一个简单的Hello world程序就可以比较出来:

#include <stdio.h>
int main()
{
    printf("Hello, world\n");
    return 0;
}
  • 用BCC 5.5编译得到的程序是51.0 KB (52,224 bytes)
  • 用VC 6.0编译得到的程序是40.0 KB (40,960 bytes)
  • 用TCC 0.9.25编译得到的程序是1.50 KB (1,536 bytes)

编译出来的程序的大小几乎可以和汇编语言写的相媲美,实乃编译病毒代码的最佳选择。很小很强大,不是么?

火狐(FireFox)中的onkeydown事件

2010年11月27日,星期六

昨天在Kaisir.Wang的文章里留言,我在输入C++的大写字母C时习惯性的按下了Shift+c,竟然弹出了个Hello World窗口。按照他的回复,这是他博客里的彩蛋。汗,一点也不好玩。

然后我把那段JavaScript代码找出来了,如下:

document.onkeydown=onkey;
function onkey(){
    if ((event.shiftKey)&&(event.keyCode==67))
    alert("Hello World!");
}

他后面又回复说这代码在火狐下无效,于是我Google了一下,原来是因为onkeydown事件在IE和FireFox的实现不一样。

Browser differences: Internet Explorer uses event.keyCode to retrieve the character that was pressed and Netscape/Firefox/Opera uses event.which.

IE用event.keyCode返回按下的按键,而Netscape/Firefox/Opera用的是event.which。

原因已找到,把代码稍微修改一下:

document.onkeydown = function(e) {
    e = e ? e : window.event;
    var keyCode = e.which ? e.which : e.keyCode;
    if(e.shiftKey && keyCode == 67)
        alert("Hello World!");
}

我还专门装了个FireFox测试,通过。

参考链接:onkeypress Event

C语言中size_t的陷阱

2010年11月26日,星期五

今天写了一个类似这样的程序:

#include <stdio.h>
#include <string.h>
int main()
{
    int i = -1;
    if(i > strlen("Demon"))
        printf("Hello World");
    else
        printf("Hello Demon");
    return 0;
}

输出的竟然是Hello World!-1 > 5?!

仔细想想,原来问题出在strlen上,strlen返回的类型是size_t,size_t的定义为:

typedef unsigned int size_t;

即无符号的整型,而i的类型是int,即有符号的整型。当有符号整型和无符号整型进行运算时,有符号整型会先自动转化成无符号。-1转化成无符号数为4294967295,远远大于5。

今后遇到有符号数和无符号数之间的运算时要千万小心。