Rise的自留地

记录生活中的点滴,分享编程技术和游戏开发经验。

0%

电视《雍正王朝》讲了这么一个故事:大将军年羹尧奉命到青海平叛,清军因路途遥远,军耗巨大,因此力求速战速决。但叛军避开锋芒,东躲西藏,年羹尧没有办法找到叛军决战。这时,朝廷内外压力越来越大,年羹尧陷入困境。这是一位谋士对年说:我知道叛军在那里。年大喜。这位谋士指出,敌人就在不远处的一座皇封寺庙里。年不信,谋士不慌不忙地说:这就是灯下黑,离自己越近就越不可能意识到,但却是最可能的地方。果然,大军一出,大获全胜。

我想讲一些关于程序员对自身认识的故事,这些故事都和灯下黑有关。只要正确认识自己,道理非常简单,但是,到处都可以看到灯下黑的故事。

某程序员,有一天接到一个任务:公司的有一个产品的文件太大了,要求采用压缩算法,减少尺寸,最好能压缩20%。

程序员兴高采烈地接受了任务:以前没玩过压缩算法,这下可以学习新东西了!研究了几个月后,他觉得差不多了,就交给了项目经理。项目经理正等着呢,高兴坏了,拿着演示文件就去找产品经理。产品经理开始挺高兴,看完脸就拉下来了。打开文件,把所有的文件尺寸一算,很淡淡的说:“才压缩了10%,有什么用啊!”

程序员愣住了,“不会吧!我看过的,压缩了 20%!”

产品经理指着文件列表说:“你看,某文件是压缩了20%,可你的压缩算法增加了一个动态库文件,尺寸还不小,总共加起来,不就只减少了10%吗?”


各位看官,这是不是软件公司里经常发生的情形?

这种失败的成因当然是复杂的,有沟通管理方面的问题,也有程序员能力的问题。我今天想要说的是程序员认识方面的问题。

继续故事:

项目经理很没面子,回去就和程序员找原因。项目经理是老程序员了,直话直说;终于弄清楚的事情的本质:

第一,这位程序员一个的时间读了很多关于压缩算法的书,会了不少算法。可是从来没比较过算法的优劣。这老兄觉得研究算法很有趣,乐此不彼,写了好几个实现。

第二,这位老兄在最后几天才想起来20%的目标,也没太放在心上,看看差不多就拿出来了。


这是典型的程序员的认识问题,重知识而轻技术。

先从是么是知识,什么是技术说起。

知识就是知道,你知道了某件事是怎么回事,就是有了知识。

技术就是你能做出来,做得好叫技术好,做的不好叫技术差。


怎么写操作系统?看完操作系统原理,再苦读完源代码,这叫有知识了。如果有本事把任务调度、内存管理、IO什么的都写出来,还能写得稳定,快速,可扩展,那是有技术。有知识和有技术可差远了。早年我在工厂实习,要挫一个圆孔,拿着内锉刀干了一天,只挫了一个椭圆;师父来了,三分钟,比冲床冲出来还圆!我是个好学徒,使用锉刀的知识全记住的,可以写一篇内圆挫使用大全。知识是有了,可没这个技术。

程序员也一样。什么C++,Java,.net,什么STL,Struts,Spring,就是门门都满分,这也就是有知识。算不算技术好呢?差远了。软件工程师界就专门出这种不会写程序的“高手”。我遇到一位老兄,精通Java知识,从虚拟机到各类框架,概念,无所不同,谈起Java来,没人说的过他。可是他的代码永远Bug最多,而且都是最简单的Bug,什么逻辑不对啊,功能没实现啊,UI不对啊。他的领导只有又好气又好笑。问下去,发现这老兄写了几个程序文件以后,就不感兴趣了,因为所用的技术没什么不知道的了。所以马马虎虎交差。


说到底,写程序是个手艺活,就和古代的匠人一样,是要讲工艺的。比如一个玉匠,能打造栩栩如生的玉孔雀,那得打的好!要是一个玉匠说,这些手艺我都知道了,重复做东西没劲,将就着给客人做出来吧!那他还不吃西北风!

可是,十几年来,程序员界有的是这样的人,还引发大规模争论。象什么C++和Java之争啦,J2EE和.Net之争啦。你看里边的帖子,不停有人赌这个阵营那个阵营,有发誓一辈子做C++的,有发誓打倒.Net。我还奇怪了,专门没人效忠机器码的,那不是最难最有“学问”吗?这都是在争论什么知识最重要。可是啊,很少有人谈谈怎么做好产品的。


现在程序员最大的问题就是太看重知识,拼命追逐新玩意,而忽略了身边的够得着东西。好,什么C++,Window API都知道了,东西也弄出来了,可是三天两头崩溃,还找不到原因?为什么?有没有看看代码,看看是不是某函数写了2000行,自己都看不懂?是不是全局变量乱用?是不是没考虑前后兼容性?没考虑冗余和故障恢复?

末了再回到开头的故事:

项目经理回去和程序员再重新设计,又多花了一个月,终于达到了目标。但因为这个部分是一个大项目的一部分,整个项目不得不延迟了一个月。

年底考评的时候,项目经理给程序员打了一个及格;程序员不服,告到总经理那里。总经理说:“你知足吧,给你打及格已经看在你干的很辛苦的份上了,因为你没有按时完成,整个项目延迟了一个月,这帐都没找你算呢。”程序员颓然。

点击访问此系列文章

由于本人有很好的C++基础,所以想从C++直接转到C#.

 

1.       布尔值:在C++中,bool类型实质上是一个整数。在C#中,不存在bool类型与其他类型之间的相互转换。

bool 关键字是System.Boolean的别名.它用于声明变量来存储布尔值truefalse.

可将布尔值赋给bool变量.也可以将计算为bool类型的表达式赋给bool变量.

C++,bool类型的值可转换为int类型的值;也就是说,false等效于零值,true等效于非零值.C#,不存在bool类型与其它类型之间的相互转换.例如,下列if语句在C#中是非法的,而在C++中则是合法的:

int x = 123;

if (x) // C# 是错误的

{ printf("The value of x is nonzero."); }

若要测试int类型的变量,必须将该变量与一个值(比如零)进行显式比较,如下所示:

int x = 123;

if (x != 0) // C# 中容许

{ printf(“The value of x is nonzero.”); }

2.       long类型:long类型在C#中为64位,而在C++中为32位。

long关键字表示一种整形,该类型根据下表显示的大小和范围存储值。

long取值范围-92233720368547758089223372036854775807,long类型中使用后缀L

long long2 = 4294967296L;

当使用后缀L时,将根据整数的大小确定它的类型为long还是ulong

3.       switch语句:与C++中的switch语句不同,C#不支持从一个case标签贯穿到另一个case标签。

switch语句是一个控制语句,它通过将控制传递给其体内的一个case语句来处理多个选择和枚举。

case标签可以从一个case标签贯穿到另一个:

using System;

class SwitchTest

{

        static void Main()

        {

               int n = 2;

               switch(n)

               {

                      case 1:

                      case 2:
                      case 3:

                             Console.WriteLine(“It`s 1, 2, or 3.”);
                             break;

               default:

                      Console.WriteLine(“Not sure what it is.”);

                      break;

               }

        }

}

OUT: It`s 1, 2, or 3.

4.       委托:C#中的委托大致类似于C++中的函数指针,是类型安全可靠的.

委托类型声明的格式如下:

public delegate void TestDelegate(string message);

delegate关键用于声明一个引用类型,该引用类型可用于封装命名方法或匿名方法.委托类似于C++中的函数指针;但是,委托是类型安全和可靠的.

5.       extern关键字:在C++中,extern用于导入类型。在C#中,extern用于为使用同一程序集的不同版本创建别名。

extern修饰符用于声明在外部实现的方法。extern修饰符的觉用法是在使用Interop服务调入非托管代码DllImport属性一起使用;在这种情况下,该方法还必须声明为static,如下面的所示:

[DllImport(“avifil32.dll”)]

private static extern void AVIFileInit();

abstractextern修饰符一起使用来修改同一成员是错误的。使用extern修饰符意味着方法在C#代码的外部实现,而使用abstract外包符意思着在类在未提供方法实现。

6.       static关键字:在C++中,static既可用于声明类级实体,也可用于声明特定于某模块的类型。在C#中,static仅用于声明类级实体。

使用static修饰符声明属于类型本身而不是属于特定对象的静态成员。static修饰符可用于类、字段、方法属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型。

备注:

l          常数或者类型声明隐式地静态成员。

l          不能通过实例引用静态成员。然而,可以通过类型名称引用它。

l          尽管类的实例包含该类所有实例字段的单独副本,但每个静态字段只有一个副本。

l          不可以使用this来引用静态方法或属性访问器。

l          如果对类应用static关键字,则该类的所有成员都必须是静态的。

l          类(包括静态类)可以有静态构造函数。在程序开始和实例化类之间的某个时刻调用静态构造函数。

7.       C#中的Main方法和C++中的main函数的声明方式不同。在C#中,它是大写的,并且始终是static的。此外,在C#中,对处理命令行参数的支持要可靠得多。

Main方法是程序的入口点,您将在那里创建对象和调用其他方法。一个C#程序中只能有一个入口点。

class TestClass

{

    static void Main(string[] args)

    {

        // Display the number of command line arguments:

        System.Console.WriteLine(args.Length);

    }

}

概述:

l          Main方法是程序的入口点,程序控制在该方法中开始和结束。

l          该方法在类或结构的内部声明。它必须为静态方法,而不应该为公共方法。

l          它可以具有voidint返回类型。

l          声明Main方法时既可以使用参数,也可以不使用参数。

l          参数可以作为从零开始索引的命令行参数来读取。

l          CC++不同,程序的名称不会被当作第一个命令参数。

8.       C#中,只有在unsafe模式下才允许使用指针。

unsafe关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。
可以在类型或成员的声明中使用unsafe修饰符。因此,类型或成员的整个正文范围均被视为不安全上下文。若要编译不安全代码,必须指定/unsafe编译器选项。无法通过公共语言运行库验证不安全代码。

9.       foreach关键字使您可以循环访问数组和集合。

foreach语句为数组或对象集合中的每个元素重复一个嵌入语句级。foreach语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用。

备注:

嵌入语句为数组或集合中的每个元素继续执行。当为集合中的所有元素完成有迭代后,控制传递给foreach块之后的下一个语句。

在此示例中,使用foreach显示整数数组的内容。

// cs_foreach.cs

class ForEachTest

{

        static void Main(string[] args)

        {

               int[] fibarray = new int[] {0, 1, 2, 3, 5, 6, 18};

               foreach(int i in fibarray)

               {

                      System.Console.WriteLine(i);

                     }

       }

}

       输出

0 1 2 3 5 6 18

10.    方法隐藏:C++通过继承支持方法的隐式“隐藏”。在C#中,必须使用new修饰符来显式隐藏继承的成员。

C#中,new关键字可用作运算符、修饰符或约束。

l          new运算符:用于创建对象和调用构造函数。

new运算符还用于调用值类型的默认构造函数。

不能重载new运算符。如果new运算符分配内在失败,将引发异常OutOfMemoryException

l          new修饰符:用于向基类成员隐藏继承成员。

在用作修饰符时,new关键字可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。在不使用new修饰符的情况下隐藏成员是允许的,但会生成警告。使用new显式隐藏成员会取消此警告,并记录代之派生版本这一事实。

若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并使用new修饰符该成员。例如:

public class BaseC

{

        public int x;

        public void invoke(){}

}

public class DerivedC : BaseC

{

        new public void Invoke(){}

}

在此示例中,DerivedC.Invoke隐藏了BaseC.Invoke。字段x不受影响,因为它没有被类似的名称的字段隐藏。

通过继承隐藏名称采用下列形式之一:

1.       引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成员。

2.       引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。

3.       引入类或结构的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。

对同一成员同时使用newoverride是错误的,因为这两个修饰符在含义上相互排斥。使用new会用同样的名称创建一个新成员并使原始成员变为隐藏的,而override则扩展继承成员的实现。

l          new约束:用于在泛型声明中约束可能用作类型参数的参数的类型。

new结束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。当泛型创建类型的新实例时,将此约束应用于类型参数,如下面的示例所示:

class ItemFactory<T> where T: new()

{

public T GetNewItem()

{

return new T();

}

}

当与其他约束一起使用时,new()约束必须最后指定:

using System;

public class ItemFactory<T>

where T: IComparable, new()

{}

这个事件时间很长了,但是还想转下,同时提供一种现在还能用的访问方法.
以下内容转载与博客园和本人无关.

今天,忽然听说维基百科被封了,令我感到非常震惊,赶忙输入维基百科的网址zh.wikipedia.org看看,正如预料的一样,的确是上不去了。

今日整理硬盘无意发现刚学windows编程时写的一段代码,用于在windows下异步读写硬盘用的.
可能网上已经有类似的代码了,小弟在发一次,希望别有人用这做坏事.
打开硬盘有两个东西要知道,第一打开的文件名:\\\\.\\PHYSICALDRIVE0, 0代表第一块硬盘,依次1代表第二块硬盘...第二打开硬盘使用的参数OPEN_EXISTING是不可少的,至于为什么查MSDN.
先把代码发上来大家看看,读写速度还可以几秒就1G了,有空改成完成端口不知道会不会快点.
(注意以下代码不要用\\\\.\\PHYSICALDRIVE0试验,会把硬盘时的第一个G内容写成0,后果可想而知)

 1 #include <Windows.h>
 2 
 3 VOID CALLBACK MyIOCompletion(DWORD dwErrorCode,
 4                              DWORD dwNumberOfBytesTransfered,
 5                              LPOVERLAPPED lpOverlapped
 6                              );
 7 
 8 BOOL ReadHardDisk(char* disk);
 9 
10 int __stdcall WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
11 {
12     //ReadHardDisk("\\\\.\\PHYSICALDRIVE0");
13     ReadHardDisk("C:\\a.dat");        // 如果要试试,先建立文件,要不会出错
14 
15     
16 
17     return 0;
18 }
19 
20 VOID CALLBACK MyIOCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped )
21 {
22     //TRACE("write disk succeed.");
23 }
24 
25 BOOL ReadHardDisk(char* disk)
26 {
27     HANDLE hHead;
28 
29     hHead = CreateFile(disk, GENERIC_WRITE, FILE_SHARE_WRITE, 
30         NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
31     if (INVALID_HANDLE_VALUE == hHead)
32     {
33         return FALSE;
34     }
35 
36     BYTE *pbWrite = new BYTE[1024 * 1024];    // 1M
37     OVERLAPPED overlap;
38     
39 
40     for (int i = 0; i < 1024; i++)            // 1024 也就是 1G
41     {
42         overlap.Offset = (1024 * 1024* i;
43         overlap.OffsetHigh = 0;
44         overlap.hEvent = NULL;
45         WriteFileEx(hHead, pbWrite, 1024 * 1024&overlap, MyIOCompletion);
46         while(WAIT_IO_COMPLETION != SleepEx(0, TRUE))            // 在这里可能加点东西做点别的事情
47         {
48             Sleep(0);    // 切换下时钟
49         }
50     }
51 
52     CloseHandle(hHead);
53     delete pbWrite;
54     
55     return TRUE;
56 }
57 

    GDI+绘制图片时是可以设置绘图清晰度的,清晰绘制比较占系统资源,普通模式绘制速度比较快,这个靠自己权衡了。今天在以前做的一个缩略图生成函数里加了GDI+清晰度设置的代码。
    其实设置清晰度很简单,只要加上一下三行代码,就可以让生成的缩略图和PhotoShop生成的效果一样了:

前段时间做了一个图片透明画的代码,基本思路是使用ColorMatrix设置位图的Alpha通道,使其透明化。这类代码可能高手都懒得写,像我等菜鸟要用时就得费一番周则研究了,所以我把做完的代码发上来,大家有需要用的就拿去用,如果高兴的话还可以评论里说声加油之类的话,呵呵。

    (上海讯)中国评书表演艺术家单田芳前日在上海表示,今年五月在上海电台开播的评书《老店风云》是他的收山之作。这位72岁高龄、一生说书百部的艺术家笑称,评书与流行文化比起来是“人比人得死、货比货得扔”。
    中新社报道,单田芳说他近日在北方某城市演出时,看到当地为香港某歌星的演唱会配备了4000名警力维持秩序,而他自己演出的场子里却“一个警察也没有”。当那位香港歌星出场时,观众席中竟有“粉丝”激动至休克,而他说了50余年评书“却一个休克的也没有”。
    单田芳说的《三国》,曾在中国人心目中塑造了众多古代英雄的形象,影响遍及海内外华人地区。对当今因“品三国”而声望如日中天的易中天教授, 单田芳说是“从心眼里佩服”,因为对方具有深厚的文化底蕴且说的是历史,而他自己则是“演义”,他笑着说:“易教授是不会形容吕布的穿着相貌的。” 
   单田芳在中国及海外华人中享有盛誉,其评书在中国600家电台播出,听众达两亿人。

失眠是一件非常复杂的事,有许多原因会形成失眠,不同的原因会有不同的失眠状况,也必需不同的对治方法。

当身体处於肺热状态时,嘴唇发红,必定失眠。这种失眠,只要喝喝薑茶,让身体顺利的排除寒气,肺热状态消失了,就能睡。

最近听说在中国大陆有人提议废除中医,而且还是科学界的人提出来,并且有不少人附和,经常有人问我这方面的意见。我认為在所有慢性病都还没有找到解决方案的今天,对於中医和西医做出评价都是很不智的。这些争论并不会使医学有丝毫进展,不可能从这些争议中发展出任何慢性病的治疗技术,实在没有太大的意义。