博文

一个精悍而巧妙的程序(2006-08-04 16:29:00)

摘要:近期用CreateProcess的时候出了些问题,发现第一个时间片的末尾总会有重复的指令在执行,于是想看看_beginthreadex能不能解决这个问题,无奈_beginthreadex却不接受我的线程函数,问了问v兄,v兄也说不清楚原因,给出了互斥体的方法来解决。问题虽然解决了,但是无法用_beginthreadex总让我觉得很不爽,毕竟谁知道CreateProcess什么时候会出点问题呢。于是到处搜索资料,却意外的发现了一个叹为观止的进程间的自我通信,虽然与我本来的目的相差了很多,但是这个程序巧妙的构思让我兴奋不已,不敢独享,拿出来让大家也欣赏一下: #include"iostream.h"
#include"windows.h"
static LPCTSTR g_szContinueEvent="w2kdg.EventDemo.event.Continue"; BOOL CreateChild(LPCTSTR szAppName)
{
 STARTUPINFO si;
 ::ZeroMemory(reinterpret_cast<void*>(&si),sizeof(si));
 si.cb=sizeof(si);
 PROCESS_INFORMATION pi;
 BOOL bCreateOK=::CreateProcess(szAppName,
                             "child",
           NULL,
           NULL,
    &n......

阅读全文(4234) | 评论:5

OpenGL基本框架(2006-08-04 16:09:00)

摘要: 在北大上了4节游戏动画设计的课,老师真的是很牛,也很BT,他上课只讲算法,基本上不涉及代码,竟然要我们在第8节课之前交上去一个不少于1500行代码的OpenGL/Direct3D程序,作为大作业。 众所周知,DirectX比较难,不适于初学图形学的人,而且有平台的限制。OpenGL相对简单一点,而且功能强大,是高端的工业标准。我为了能够把更多的经历放在算法上面,而不是MS“诡异”的操作上面,选择了OpenGL. 去书店搜了搜书,D3D的书倒是琳琅满目,但是OpenGL的书却不多,基本上就是那一本“红宝书”。不过翻看红宝书一看,都是console下的列子,毕竟我不想只用GL函数,windows api也是很好的东西,况且用mfc也可以让我偷点懒。 于是放弃了红宝书,决定自己上网找资料进行实践。呵呵,现在看来这个决定还是蛮正确的。 对于windows下的编程,似乎无论是win32 app还是dll,或者mfc,最重要的,也是最难的,都是那个框架。OpenGL也是如此。好在我已经饱经mfc的洗礼,明白如何下手分析框架。不过发现网上的很多程序框架都不是完全一样,不知道这里有没有什么标准?有些代码段去掉之后也仍然没有问题的。这似乎印证了csdn上的一句话:OpenGL出了错,什么都不会做; DirectX出了错,什么都做的出来。^-^ 研究了很多例子之后,我自己总结出了一个最简单、易懂的通用框架,并且给出了重要部分的注释:   /******************************by CRACKER007*******************************/     BOOL CGdlg::InitialPixelFormat()    //此函数被后面的CreateRC调用
{
 static PIXELFORMATDESCRIPTOR pfd=
 {
  sizeof(PIXELFORMATDESCRIPTOR),
   1,
   PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFF......

阅读全文(4231) | 评论:6

vc之pragma宏的简单应用(2006-08-04 16:08:00)

摘要:整理了一下msdn中关于pragma的一些用法,在此列出我认为是比较有用的一些pragma指令,并加上我的一些说明:   1 The following pragma causes the linker to search for the EMAPI.LIB library while linking. The linker searches first in the current working directory and then in the path specified in the LIB environment variable: #pragma comment( lib, "emapi" )
-----------------------------------------------------------------------
2 When the compiler encounters a deprecated symbol, it issues C4995: void func1(void) {}
void func2(void) {}
int main() {
   func1();
   func2();
   #pragma deprecated(func1, func2)
   func1();   // C4995
   func2();   // C4995
}
----------------------------------------------------------------------
3 The following code fragment uses the message pragma to display a message during compilation: #if _M_IX86 == 500
#pragma message( "Pentium processor build" )
#endif
----------------------------......

阅读全文(4394) | 评论:1

宽字符集下汉字的输出(2006-08-04 16:08:00)

摘要: vc6与devcpp确实让我难以取舍,如果两个能够很好的融合就好了。最近写宽字符输出程序的时候,它们之间又出了矛盾。哎,devcpp对标准支持的好,但是vc6使用更加方便,而且我经常要写mfc。看来是时候换vc2005了。 先把眼前的问题解决了吧,对于如何设置宽字符集,我先做一个简单的介绍:   C程序员一般是用 char 关键字像下面这样来声明一个字符串数组:
char str[100];      
像下面这样声明函数原形:
void strcpy( char *out, char *in );       
为了将上面的声明改成支持双字节的 UNICODE 字符集,可以用下面的方法:
wchar_t str[100];以及void wcscpy( wchar_t *out, wchar_t *in );   此外,微软还提供一种通过预处理指令来实现 UNICODE。每当用 Visual C++ 创建新工程时,只要确定是否支持另外一种字符集,则 AppWizard 将会在头文件中插入预处理指令。这些指令告诉编译器程序想要支持何种字符集。这样在使用VC++提供的通用数据类型时,编译器将用相应的数据类型把通用数据类型替换成所需要支持的字符集。这样很容易将代码重新编译成支持其它字符集的程序。
为了在 Visual C++ 6.0 中激活 UNICODE 标准,可以这样做:
Project=>Settings=>C/C++标签=>Preprocessor=>预处理定义中加上:
UNICODE和_UNICODE。其中_UNICODE宏用于C运行时头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常要同时定义这两个宏,因为不同的头文件可能使用不同的宏。
 
如何表示Unicode字符串常量?
字符集             实例
ANSI &......

阅读全文(4942) | 评论:2

vc6中关于模板显式特化问题的解决(2006-08-04 16:07:00)

摘要:#include <iostream.h>
#include <string.h> template<class T> T max(T t1,T t2)
{
    return (t1>t2?t1:t2);
}
typedef const char* pcc;
template<> pcc max(pcc s1,pcc s2) 
{                              
    return (strcmp(s1,s2)>0?s1:s2);
}
void main()
{
    int n=max(4,3);
    cout<<n<<endl;
    const char *p=max("bbb","aaa"); 
    cout<<p;
}   这段程序在devcpp下没有问题,调用的是特化之后的函数。但是在vc6下面却变成了通用模板函数。经过我的几次尝试,发现要加一点东西vc6才能认识: #include <iostream.h>
#include <string.h> template<class T> T max(T t1,T t2)
{
    return (t1>t2?t1:t2);
}
typedef const char* pcc;
template<> pcc max(pcc s1,pcc s2......

阅读全文(2630) | 评论:0

左值与右值(2006-08-04 16:06:00)

摘要: 什么情况下返回指针?什么情况下返回引用?指针和引用的效果一样么? 这里不仅涉及到引用的实现,也涉及到左值与右值的概念。因为返回值性质的不同决定了引用与指针必定不是相同的。相信你读过我写的这篇文章之后,会有一个比较清醒的认识。   左值(lvalue)和右值(rvalue)最先来源于C语言。最先在C语言中表示位于赋值运算符两侧的两个值,左边的就叫左值,右边的就叫右值。
比如:
int ii = 5;   //ii是左值,5是右值
int jj = ii;  //jj是左值,ii是右值
上面表明,左值肯定可以作为右值使用,但反之则不然。左值和右值的最早区别就在于能否改变。左值是可以变的,右值不能变,但是这一点在C++中已经不再成立。 在现代C++中,现在左值和右值基本上已经失去它们原本所具有的意义,对于左值表达式,通过具体名字(variant name)和引用(reference)来指定一个对象。非左值就是右值。我们来下一个定义:
左值表示程序中必须有一个特定的名字引用到这个值。
右值表示程序中没有一个特定的名字引用到这个值。
这跟它们是否可以改变,是否在栈或堆(stack or heap)中毫无关系。 1.左值
在下面的代码中:
int ii = 5;      
const int jj = ii;
int a[5];
a[0] = 100;
*(a+3) = 200;
const int& max(const int& a, const int& b) //call by reference
{
 return a > b ? a : b;
}
int& fun(int& a) //call by reference
{
 a += 5;
 return a;
}
ii,jj,a[0],*(a+3)这些值,还有函数max的返回值比如max(ii, jj),函数fun的返回值fun(ii)都是左值。因为它们都是被特定的名字所引用的值。
......

阅读全文(4824) | 评论:2

重载、隐藏与覆盖(2006-08-04 16:05:00)

摘要: 想必大家在学习c++的时候,经常会在虚函数机制那里遇到问题。搞清楚这些概念,不要被基础语法所困扰,才能顺利的深入学习。 下面我就一些容易混淆的概念作些自己的解释,解释依据于devcpp与vc的共同结果。   隐藏(Hide):
假设有:
class A
{
 public:
   void func(){}
};
class B: public class A
{
 public:
   void func(){}
};
那么,对于A* p;不管p指向A还是B,都只能调用A中的func;
同样,对于B* p;不管p指向A还是B,都只能调用B中的func;
总结:对于普通成员函数,调用的是哪个类的版本,要看指针的原型,而不是看指向对象的类型。   覆盖(Override):
假设有:
class A
{
 public:
   virtual void func(){}
};
class B: public class A
{
 public:
   void func(){}
};
那么,对于A a;p=&a;不管p是A*还是B*,都调用A中的func;
同样,对于B b;p=&b;不管p是A*还是B*,都调用B中的func;
总结:对于虚函数,调用的是哪个类的版本,要看指针指向什么类型的对象,而不是看指针的原型。   重载(Overload):
即实现同名函数。重载与类无关,更与virtual无关。一般的函数就可以实现。仅仅是返回类型不同是不能重载的,重载至少需要在参数个数、参数类型、参数顺序这三者之中的一个不同。......

阅读全文(2609) | 评论:0

字符指针的初始化(2006-08-04 16:04:00)

摘要: 初学者经常被这个问题所困惑: char *p="abc"==>"abc"是一个const char*,为什么能够赋值给char *?   很多论坛上都可以看到这样的提问帖,不过这些帖子有的讲的是错误的,有的虽然是对的,但是讲的不细致,初学者不好理解。对此,我根据我的经验,以及CSDN上的一些帖子仔细地说一下其中的道理。   按照 C/C++ 标准的描述,"abc" 是 string literal (字符字面量、字符文字量),具有静态存储性质,类型是数组类型,并且不能被改变。注意:"abc" 是一个数组类型的对象,是左值。当然左值可以转化为右值使用,就像数组类型的对象可以转化为指针一样。 虽然 "abc" 是数组类型,但是 C 和 C++ 在类型规定上是有区别的:在 C 中,"abc" 的类型是 char [4];在  C++ 中,其类型是 const char [4]。 由于数组类型可以转换为指针类型来使用,所以在 C 和 C++ 中 "abc" 可分别作为 char* 及 const char* 使用。 为了兼容c中char *p="abc"这种现象的存在,C++特别允许初始化时const char*到char*的自动转换。但是这条规则被 C++ 标明为 “Deprecated”,不被推荐使用。 综上所述,
在 C 中:char *p="abc"是完全合乎规则的事情
在 C++ 中:由于有特殊规定,所以这样也可以。 但在c++中要注意:
char *p="abc" 能不能编译通过要看你使用的编译器。鉴于大量遗留代码的存在,大部分编译器允许其通过,或者给个警告。当然,程序员自己必须保证绝不去修改其值:
a. 程序员不应该在代码中出现*p='A'这样的语句。这是当初约定好了的:编译器允许char *p="abc"通过,而程序员保证不去修改它。
b. *p='A'编译时应该允许通过,因为单就这条语句而言,它完全合法。
c. 运行时*p='A'能不能通过要看实际的运行环境,包括你使用的操作系统、编译器、编译器选项 等等,一句话,其运行结果由不得你,且不应该由你去关心,因为这种行为本身已经违反约定了。 ......

阅读全文(5280) | 评论:4