2011年3月27日星期日

x&(x-1)

来源: 原文链接


昨天在淘宝招聘会上遇到的这道笔试题:求下面函数的返回值 -- 统计1的个数

int func(int x)
{
    int countx = 0;
    while(x)
    {
        countx++;
        x = x&(x-1);
    }
    return countx;
}

假定x = 9999
10011100001111
答案: 8

思路: 将x转化为2进制,看含有的1的个数。
注: 每执行一次x = x&(x-1),会将x用二进制表示时最右边的一个1 变为0,因为x-1将会将该位(x用二进制表示时最右边的一个1)变为0。

判断一个数(x)是否是2的n次方
-------------------------------------

#include <stdio.h>

int func(int x)
{
    if( (x&(x-1)) == 0 )
        return 1;
    else
        return 0;
}

int main()
{
    int x = 8;
    printf("%d\n", func(x));
}

注:
(1) 如果一个数是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0。
(2) ==优先级高于&

运行级别及Ubuntu启动进入文本模式

Update 20111028 以前转载的内容可能只适用于某个版本(至少Ubuntu 9.10就不适用了),又找到一些方法,经试用可行,记录在此。 来源:ubuntu 开机启动终端 字符模式 文本模式 注意 debian类系统的启动级别和往常的redhat等不同 rc0表示关机rc6表示重启 rc1表示单用户模式 rc2-rc4表示多用户模式 ( 0 关机 1 单用户模式 2 不带网络的多用户模式 3 带网络的多用户,也就是所谓的纯字符模式 4 保留,用户可以自给定义 5 图形界面的多用户模式 6 重起系统 ) 所以如果你想要启动到终端的话 你只需要关闭gdm的服务 我介绍一个简单的方法 代码: sudo apt-get install sysv-rc-conf sudo sysv-rc-conf 然后在里面找到一个叫做gdm的服务,别且在所有级别关闭它 然后q就ok了 找到的第二种方法 用nano编辑 /etc/X11/default-display-manager,把/usr/sbin/gdm注释掉,即在前面加个#号,改成#/usr/sbin/gdm,然后在加一行false这样保存既可. 完整的是这样: #/usr/sbin/gdm false 修改后重启,这样启动就是字符界面了。 找到的第三种方法 # 0 - halt (Do NOT set initdefault to this) 关机(不要设置为默认) # 1 - Single user mode 单用户模式 # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) 多用户模式,但不支持NFS # 3 - Full multiuser mode 完全的多用户模式 # 4 - unused 没用到 # 5 - X11 图形界面 # 6 - reboot (Do NOT set initdefault to this) 重启(不要设置为默认) RedHat中要改变启动级别,只要修改/etc/inittab。Ubuntu有点不一样,网上的方法也很多,试过其中一种。   You need to open the /etc/default/grub file, locate the following line:   GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"   and change it to:   GRUB_CMDLINE_LINUX_DEFAULT="quiet splash text"   update-grub 即编辑/etc/default/grub文件,将GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"改为GRUB_CMDLINE_LINUX_DEFAULT="quiet splash text",然后更新一下grub。 方法三还可以。如果想用这种方法永远启动到字符终端模式,则可以修改/boot/grub/grub.cfg,在相应的位置添加txt参照即可。但是grub.cfg是 自动生成的,所有的在里面的修改都可能被其它的操作覆盖掉,比如update-grub命令,如果不想被覆盖,则修改/etc/default/grub 把 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" GRUB_CMDLINE_LINUX="" 改成 GRUB_CMDLINE_LINUX_DEFAULT="text" GRUB_CMDLINE_LINUX="" 然后再运行一下update-grub命令,它会自动添加上text参数到内核参数中。 说明: 1,无论使用什么方式启动到字符终端模式,你都可以使用命令startx命令来启动Xwindow 2,在10.04 lucid 下测试成功 参数的含义(个人猜测,没有在网上找到相关内容) quiet 阻止内核输入到命令行 splash 显示启动画面,如ubuntu logo text 启动到字符终端模式 我的同时写上quiet 和text就起不来,停在checking battery status 下面不动了,也可以我为了测试等待的时间不够长,虽然不动了,可以按CTRL+ALT+DELETE重新启动。 文本与桌面模式切换: 文本模式登陆后,在普通用户权限下执行startx,进入到桌面模式。 一定要在普通用户权限下,root权限下startx,桌面模式都是默认设置,不加载个人设置! 桌面到文本的切换: Ctrl+Alt+F1,切到文本界面,执行Ctrl+c,结束掉刚才启动的X server!
以下为旧文 来源:未知 Linux系统有7个运行级别(runlevel)  (注意下文,debian系衍生的linux 运行级不一样) 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆 运行级别2:多用户状态(没有NFS) 运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式 运行级别4:系统未使用,保留 运行级别5:X11控制台,登陆后进入图形GUI模式 运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动 运行级别的原理: 1。在目录/etc/rc.d/init.d下有许多服务器脚本程序,一般称为服务(service) 2。在/etc/rc.d下有7个名为rcN.d的目录,对应系统的7个运行级别 3。rcN.d目录下都是一些符号链接文件,这些链接文件都指向init.d目录下的service脚本文件,命名规则为K+nn+服务名或S+nn+服务名,其中nn为两位数字。 4。系统会根据指定的运行级别进入对应的rcN.d目录,并按照文件名顺序检索目录下的链接文件      对于以K开头的文件,系统将终止对应的服务      对于以S开头的文件,系统将启动对应的服务 5。查看运行级别用:runlevel 6。进入其它运行级别用:init N 7。另外init0为关机,init 6为重启系统 ____________________________________________________________________________________________ 因为debian 系衍生出来的linux 一向是没有使用/etc/inittab 作为登入状态文档来使用的。但是虽然没有系统默认没有这个文件,但是你可以自己建一个inittab文件。 因为从/etc/event.d/中的rc-default文件中代码可以看出: script runlevel --reboot || true if grep -q -w -- "-s\|single\|S" /proc/cmdline; then telinit S elif [ -r /etc/inittab ]; then RL="$(sed -n -e "/^id:[0-9]*:initdefault:/{s/^id://;s/:.*//;p}" /etc/inittab || true)" if [ -n "$RL" ]; then telinit $RL else telinit 2 fi else telinit 2 fi end script 系统会首先搜寻inittab文件,如果不存在,那么将运行在2级别上。所以你可以自己建个inittab文件,或者把相应的telinit 2 改为 telinit X(你想要运行的级别) 转到kubuntu之前曾经学习了一下,了解到ubuntu在6.10开始用upstart替代init,主要脚本都在/etc/event.d下面,默认情况下/etc下没有inittab文件。 刚装上kubuntu时候专门到/etc/event.d下看了一下,特别注意到rc-default这个脚本,里面有一段内容: elif [ -r /etc/inittab ] then 说明默认情况下inittab虽然不存在,但是用户建立的inittab还是会被注意到的。然后又经别人的指点看了一下/usr/share/doc/upstart/下面的文档,其中README.Debian中有这么一段内容: 这就给我这样一个印象,即虽然ubuntu用upstart替代init,但还是和init保持兼容。 今天正好需要将系统直接启动到字符界面下,即不启动kdm。 edit the /etc/inittab file 那就试试自建一个inittab文件,并按照以前的习惯写入一行id:3:initdefault: ,保存后重新启动,结果发现毫无变化,依然启动到桌面,有点纳闷,难道inittab不起作用?在终端里输入runlevel检查当前状态,显示 N 3,说明inittab有效果,那是什么原因呢? 将刚才建立的inittab移除,将系统恢复到之前的状态并重新启动,再用runlevel检查,显示 N 2,说明ubuntu系统的default runlevel可能是2,这和我以前的常识有些冲突,看来又需要学习了。 先去分别查看/etc/rc2.d至rc5.d下的内容,发现基本一致,都启动了kdm。这与其他的linux发行版不太一致,通常runlevel 3是Multi user mode,即直接登录到字符界面;而runlevel 5是Multi user mode with GUI,即登录到图形界面。 后来在Debian的FAQ里面搜索到这样的内容: 0(halt the system) 1(single-user mode) 2through5(various muli-user modes),and 6(reboot the system) 小区别就在这里了,看来debian以及衍生出来的发行版,如ubuntu的default runlevel确实是2,而且id 2至5都是一样的。 真相大白,再次建立inittab,写入id:3:initdefault: ,然后进入/etc/rc3.d,重命名S30gdm,重新启动系统,如愿以偿进入字符界面。 

2011年3月23日星期三

在VC9.0中实现C++模板类头文件和实现文件分离的方法

来源:原文链接


如何实现C++模板类头文件和实现文件分离,这个问题和编译器有关。

引用<>里的观点:1)标准C++为编译模板代码定义了两种模型:“包含”模型和“分别编译”模型。2)所有编译器都支持“包含”模型

,某些编译器支持“分别编译”模型。

问题的提出:(帖子在:http://topic.csdn.net/u/20101215/15/f4f270f2-f0f9-4c5f-8765-1bfde2aeebbf.html)

第一种方法:按C++primer中的“包含”模型,在定义模板类的头文件中的末行用语句:#include "template_compile.cpp"

在类模板头文件template_compile.h中:


template  
class base
{
public:
    base() {};
    ~base() {};
    T add_base(T x,T y);
};
#include "template_compile.cpp"


在类模板的实现文件template_compile.cpp中:


template  
T base::add_base(T x,T y)  
{
    return x+y;
}


在使用模板的测试文件use_template.cpp中:

#include  
#include "template_compile.h"
using namespace std;
void main()
{
...
}


这种方法不能通过编译,"template_compile.cpp"文件不能"看见"“template_compile.h"文件。

然而:如果我把类模板的实现文件里代码放在类模板的头文件中,注释掉:#include "template_compile.cpp",编译和运行不会有任何错误。理论上”把类模

板的实现文件里代码放在类模板的头文件中“和”在定义模板类的头文件中的末行用语句:#include "template_compile.cpp" “是一致的,但编译器就是通不

过。

实验证明:VC9.0不支持C++primer中所说的“包含”模型。

第二种方法:bruceteen提出的:使用define

在类模板头文件template_compile.h中:


template  
class base
{
public:
  base() {};
  ~base() {};
  T add_base(T x,T y);
};
#define xxx
#include "template_compile.cpp"


在类模板的实现文件template_compile.cpp中:


#ifdef xxx
template  
T base::add_base(T x,T y)  
{
  return x+y;
}
#endif


测试文件不变。

实验证明:在VC9.0中,这种方法可以实现类模板头文件和实现文件的分离

方法三:

在类模板头文件template_compile.h中:


template  
class base
{
public:
    base() {};
    ~base() {};
    T add_base(T x,T y);
};


在类模板的实现文件template_compile.cpp中:


#include "template_compile.h"
template  
T base::add_base(T x,T y)  
{
    return x+y;
}


在使用模板的测试文件use_template.cpp中:使用#include "template_compile.cpp"


#include  
#include "template_compile.cpp"
using namespace std;
void main()
{
...
}


实验证明:在VC9.0中,这种方法可以实现类模板头文件和实现文件的分离。

另外实验证明:VC9.0不支持“分别编译”模型。

2011年3月21日星期一

“火柴棍式”程序员面试题

来源:原文链接




有时候,有些面试题是很是无厘头,这不,又有一个,还记得小时候玩的的"火柴棍游戏"吗,就是移动一根火柴棍改变一个图或字的游戏。程序面试居然也可以这么玩,看看下面这个火柴棍式的程序面试题吧。

下面是一个C程序,其想要输出20个减号,不过,粗心的程序员把代码写错了,你需要把下面的代码修改正确,不过,你只能增加或是修改其中的一个字符,请你给出三种答案。



int n = 20;
for(int i = 0; i < n; i--){
printf("-"); }

不要以为这题不是很难,我相信你并不那么容易能找到3种方法。我觉得,如果你能在10分钟内找出这三种方法,说明你真的很聪明,而且反应很快。当然,15分钟内也不赖。不过,你要是30分钟内找不到三种方法,当然,不说明你笨了,最多就是你的反应还不够快。嘿嘿。就当是玩玩吧。

下面是我的答案:


 
//第一种解法:在for循环中给n加一个负号
for(int i = 0; i < -n; i--)
//第二种解法:把 n 初始化成 -20
int n = -20;
//第三种解法:把for循环中的 i 初始化成40
for(int i = 40; i < n; i--)

不过,我要告诉你,以上这些答案都不对(我就知道你会偷看答案的),不过,顺着这些思路走很接近了。呵呵。

下面是正确答案——



//第一种解法:在for循环中给 i 加一个负号
for(int i = 0; -i < n; i--)

//第二种解法:在for循环中把 i-- 变成 n--
for(int i = 0; i < n; n--)

//第三种解法:把for循环中的 < 变成 +
for(int i = 0; i + n; i--)

其它相关的变种题如下:

  • 通过修改、增加一个字符,让其输出21个减号
  • 通过修改、增加一个字符,让其只输出1个减号
  • 通过修改、增加一个字符,让其不输出减号

(全文完)

2011年2月27日星期日

打印质数的各种算法

来源:原文链接


打印质数的算法应该是学习计算机编程的一个经典的问题,在这里想给大家展示一些方法,相信这些方法会对你的编程有一定的启发作用。请你注意几点,
  • 实际应用和教学应用有很大的差别。
  • 最后的那个使用编译时而不是运行时的方法大家可以重点看看。

教科书的示例

首先,先给一个教科书的示例。下面这个示例应该是教科书(至少是我上大学时的教科学)中算法复杂度最好的例子了。其想法很简单,先写一个判断是否是质数的函数isPrime(),然后从1到n分别调用isPrime()函数来检查。检查是否是质数的算法是核心,其简单的使用从2到n的开根的数作为除数。这样的算法复杂度几乎是O(n*log(n)),看上去不错,但其实很不经济。

#include <iostream>
using namespace std;
bool isPrime(int nr) {
for (int d = 2; (d * d) <= (nr + 1); ++d){
if (!(nr % d)){
return false;
}
}
return true;
}

int main (int argc, char * const argv[]) {
for (int i = 0; i < 50; ++i){
if (isPrime(i)){
cout << i << endl;
}
}
}


较好的算法


我们知道,我们的算法如果写成线性算法,也就是O(n),已经算是不错了,但是最好的是O(Log(n))的算法,这是一个级数级的算法,著名的二分取中(Binary Search)正是O(Log(n))的算法。通常来说,O(Log(n))的算法都是以排除法做为手段的。所以,找质数的算法完全可以采用排除法的方式。如下所示,这种算法的复杂度是O(n(log(logn)))。
示例:打印30以内的质数
一、初始化如下列表。
2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
二、把第一个数(2)取出来,去掉所有可以被2整除的数。
2  3     5     7     9    11    13    15    17    19    21    23    25    27    29
三、取第二个数(3),去掉所有可以被 3整除的数。
2  3     5     7          11    13          17    19          23    25          29
四、取第三个数(5),因为4已经被去除了,再去掉所有可以被5整除的数。
2  3     5     7          11    13          17    19          23                29
接下来的数是7,但是7的平方是49,其大于了30,所以我们可以停止计算了。剩下的数就是所有的质数了。

实际应用的算法

实际应用中,我们通常不会使用上述的两种算法,因为那是理论学院派的算法。实际中的算法是,我把质数事先就计算好,放在一个文件中,然后在程序启动时(注意是在启动时读这个文件,而不是运行时每调用一次就读一次文件),读取这个文件,然后打印出来就可以了。如果需要查找的化,二分查找或是hash表查找将会获得巨大的性能提升。当然,这样的方法对于空间来说比前面两个都要消耗得大,但是你可以有O(log(n))或是O(1)的时间复杂度。
所以,我想在这里提醒大家——实际和理论的的方法很不一样的,千万不要读书读成书呆子。在游戏编程的世界里,大量的数据都不是运行计算的,而都是写在文件中的。比如,一个火焰效果,一个人物跑动的动作,都是事先写在文件中的。

使用编译时而不是运行时

下面这个例子(本例参考于这里)你需要注意了,这是一个高级用法,使用模式来在编译时计算质数,而不是运行时。这种技术使用了C++编译器对模板的特化时的处理来生成自己相要的结果。这种方法在技术上是相当Cool的,但并不一定实用,这里只是想像大家展示这种用法。这是C++的最骨灰级的用法了。
请看下面的两个模板类,第一个模板以递归的方式检查是否是质数,第二个方法是递归的退出条件(当N=1时),对于模板的重载,请参看相关的C++书籍。
template<int N, int D = N - 1> 
struct isPrime {
enum {
result = (N % D) && isPrime<N, D-1>::result
};
};

template<int N>
struct isPrime<N, 1> {
enum {
result = true
};
};

于是,通过这个模板,我们可以使用下面的代码来检查是否是质数:
if (isPrime<3>::result)
cout << "Guess what: 3 is a prime!";

下一步,我们需要打出一个区间内的质数,所以,我们需要继续设计我们的print模板。
template<int N, bool ISPRIME> 
struct printIfPrime {
static inline void print() {}
};
template <int N>
struct printIfPrime<N, true> {
static inline void print() {
std::cout << N << endl;
}
};

从上面的代码中,我们可以看到,我们的第一个实际是什么也没做,而第二个有输出,注意第二个的模板参数中有一个true,其意味着那个质数的判断。于是我们就可以给出下面的代码来尝试着打印出一段区间内的质数:(请不要编译!!因为那会让编译器进入无限循环中,原因是printPrimes会不停地调用自己永不停止)

template<int N, int MAX>
struct printPrimes {
static inline void print() {
printIfPrime<N, isPrime<N>::result>::print();
printPrimes<N + 1, MAX>::print();
}
};

为了避免这个问题,你需要再加一个模板类,如下所示。这样当N变成MAX的时候,递归就结束了。

template<int N>
struct printPrimes<N, N> {
static inline void print() {
printIfPrime<N, isPrime<N>::result>::print();
}
};


最后,让我们来看看最终的调用:
int main (int argc, char * const argv[]) {
printPrimes<2, 40>::print();
return 0;
}

这个方法很NB,但是有两个问题:
  • 比较耗编译时间。
  • 不能在运行时输入MAX的值。
不过,相信这种玩法会启动你很多的编程思路。
(全文完)

2011年2月10日星期四

C++中数组参数详解

在C++中,数组永远不会按值传递。它是传递第一个元素(准确地说是第0个)的指针。
例如,如下声明:
  void putValues(int[10]);
被编译器视为:
  void putValues(int*);
数组的长度与参数声明无关。因此,下列三个声明是等价的:
  void putValues(int*);
  void putValues(int[]);
  void putValues(int[10]);
因为数组被传递为指针,所以这对程序员有两个含义:
1、在被调函数内对参数数组的改变将被应用到数组实参上而不是本地拷贝上。当用作实参的数组必须保持不变时,程序员需要保留数组的拷贝。函数可以通过把参数类型声明为const来表明不希望改变数组元素:
  void putValues(const int[10]);
2、数组长度不是参数类型的一部分。函数不知道传递给它的数组的实际长度,编译器也不知道,当编译器对实参类型进行参数类型检查时,并不检查数组的长度。
例如:
void putValues(int[10]); //视为int*

int main()
{
    int i, j[2];
    putValues(&i); //ok:&i是int*; 潜在的运行错误
    putValues(j);  //ok:j被转换成第0个元素的指针
    // 实参类型为int*:潜在的运行错误
    return 0;
}
 
参数的类型检查只能保证putValues()的再次调用都提供了int*型的实参。类型检查不能检验实参是一个10元素的数组。
习惯上,C风格字符串是字符的数组,它用一个空字符编码作为结尾。但是所有其他类型,包括希望处理内含字符的字符数组,必须以某种方式在向函数传递实参时使其知道它的长度。一种常见的机制是提供一个含有数组实参的长度的额外参数。例如:
 void putValues(int[], int size);
int main()
{
    int i,j[2];
    putValues(&i, 1);
    putValues(j, 2);
    return 0;
}

另外一种机制是将参数声明为数组的引用。当参数是一个数组类型的引用时,数组长度成为参数和类型的一部分,编译器检查数组实参的长度与在函数参数类型中指定的长度是否匹配。
// 参数为10个int的数组
// parameter is a reference to an array of 10 ints
void putValues(int (&arr)[10]);
int main()
{
    int i, j[2];
    int a[10];
    putValues(i); // 错误:实参不是10个int的数组
    putValues(j); // 错误:实参不是10个int的数组
    putValues(a); // 正确
    return 0;
}
因为数组的长度现在是参数类型的一部分,所以putValues()的这个版本只接受10个int的数组。这限制了可以作为实参被传递给putValues()的数组的种类。但是,它也使函数的实现更加简单。

ShowWindow的疑问

本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:81]
发信人: novice (Android), 信区: VC 
标  题: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月06日23:59:04 星期天), 站内信件 WWWPOST 

BOOL WINAPI ShowWindow( 
  __in  HWND hWnd, 
  __in  int nCmdShow 
); 
中 nCmdShow,MSDN中有这么段话: 
This parameter is ignored the first time an application calls ShowWindow, if  
the program that launched the application provides a STARTUPINFO structure.  
Otherwise, the first time ShowWindow is called, the value should be the  
value obtained by the WinMain function in its nCmdShow parameter. 

要怎么理解??? 

我的理解是,如果我用CreateProcess创建某程序,该程序就是创建个窗口,别无其他功 
能,调用CreateProcess时提供了STARTUPINFO si,并将相应的标志位设置si.dwFlags = 
 STARTF_USESHOWWINDOW,si.wShowWindow = SW_SHOWMINIMIZED. 
这样的话,即使被创建的程序第一次调用ShowWindow时传入参数 SW_SHOWMAXIMIZED ,程 
序也应该刚开始是最小化的。因为按照文档说明,参数该被忽略。 

但实际试验了一下,还是会出现最大化得窗口。不知道我哪里理解错误? 

-- 

本 文:[转寄][转贴][删除][修改][回复][作者:CrLF][人气:7]
发信人: CrLF (CrLF(落羽猫)), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月07日13:26:12 星期一), 站内信件 WWWPOST 

注意认真读文档:if the program that launched the application provides a  
STARTUPINFO structure. 

典型的提供STARTUPINFO的方法如:建立一个快捷方式,通过双击快捷方式启动。 

-- 

本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:2]
发信人: novice (Android), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月07日21:04:18 星期一), 站内信件 WWWPOST 

调用CreateProcess时,给 STARTUPINFO 赋值,不算提供STARTUPINFO 么? 

-- 


本 文:[转寄][转贴][删除][修改][回复][作者:CrLF][人气:5]
发信人: CrLF (CrLF(落羽猫)), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月08日13:40:44 星期二), 站内信件 WWWPOST 

之前理解错了。查了一下,使用STARTUPINFO 里提供的wShowWindow的条件是: 

第一种情况:ShowWindow的参数设为SW_SHOWDEFAULT 

第二种情况:满足以下条件,系统认定为主窗口: 
1. 设置了 STARTF_USESHOWWINDOW.  
2. 窗口是顶级窗口、无所有者、有WS_CAPTION、不是系统模态窗口 
这种情况下若ShowWindow 的参数为 SW_SHOWNORMAL 或 SW_SHOW,则使用你给定的参数. 
  

于是SW_MAXIMIZE不在此列………… 

好吧,MSDN的文档不全…… 
-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 60.18.151.157] 
※ 修改:・CrLF 于 2011年02月09日17:24 修改本文・[FROM: 60.18.151.188]
novice
69307364
本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:6]
发信人: novice (Android), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月08日16:27:05 星期二), 站内信件 WWWPOST 

不好意思,没明白你的意思。我能理解,在你列举的两种情况下,如果给ShowWindow提 
供SW_SHOWDEFAULT或者SW_SHOWNORMAL使得窗口按照STARTUPINFO的wShowWindow显示。 

我不能明白的是,MSDN文档里说的,第一次调用ShowWindow忽略nCmdShow参数的情况。 
对于“忽略”一词,我的理解是不管传入什么值,它都按照固定的方式显示。 

调用CreateProcess时给STARTUPINFO赋值,不算提供STARTUPINFO么? 

【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】 
: 之前理解错了。查了一下,使用STARTUPINFO 里提供的wShowWindow的条件是:
: 
: 第一种情况:ShowWindow的参数设为SW_SHOWDEFAULT
: 
: 第二种情况:满足以下条件,系统认定为主窗口:
: 1. 设置了 STARTF_USESHOWWINDOW. 
: 2. 窗口是顶级窗口、无所有者、有WS_CAPTION、不是系统模态窗口
: 3. ShowWindow 的参数为 SW_SHOWNORMAL 或 SW_SHOW. 
: 
: 于是SW_MAXIMIZE不在此列…………
: 
: 好吧,MSDN的文档不全……
-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 125.78.224.32] 
※ 修改:・novice 于 2011年02月08日16:28 修改本文・[FROM: 125.78.224.32]
CrLF
53453131364

本 文:[转寄][转贴][删除][修改][回复][作者:CrLF][人气:5]
发信人: CrLF (CrLF(落羽猫)), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月08日18:11:36 星期二), 站内信件 WWWPOST 

不是,我查给你的规则是实际的规则(系统实际是这样做的)。msdn文档写的含糊 :) 

信我查的好了。写msdn文档的人肯定没有写windows的人知道的清楚:P 


【 在 novice (Android) 的大作中提到: 】 
: BOOL WINAPI ShowWindow(
:   __in  HWND hWnd,
:   __in  int nCmdShow
: );
: 中 nCmdShow,MSDN中有这么段话:
: This parameter is ignored the first time an application calls ShowWindow, if 
: the program that launched the application provides a STARTUPINFO structure. 
: Otherwise, the first time ShowWindow is called, the value should be the 
: value obtained by the WinMain function in its nCmdShow parameter.
: 
: 要怎么理解???
: 
: 我的理解是,如果我用CreateProcess创建某程序,该程序就是创建个窗口,别无其他功
: 能,调用CreateProcess时提供了STARTUPINFO si,并将相应的标志位设置si.dwFlags =
:  STARTF_USESHOWWINDOW,si.wShowWindow = SW_SHOWMINIMIZED.
: 这样的话,即使被创建的程序第一次调用ShowWindow时传入参数 SW_SHOWMAXIMIZED ,程
: 序也应该刚开始是最小化的。因为按照文档说明,参数该被忽略。
: 
: 但实际试验了一下,还是会出现最大化得窗口。不知道我哪里理解错误?

-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 60.18.151.146]
novice
69307364
本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:3]
发信人: novice (Android), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月08日20:18:32 星期二), 站内信件 WWWPOST 

那意思是 ShowWindow第一次调用与后续调用没区别? 

【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】 
: 不是,我查给你的规则是实际的规则(系统实际是这样做的)。msdn文档写的含糊 :)
: 
: 信我查的好了。写msdn文档的人肯定没有写windows的人知道的清楚:P
: 
: 
: 【 在 novice (Android) 的大作中提到: 】
: : BOOL WINAPI ShowWindow(
: :   __in  HWND hWnd,
: :   __in  int nCmdShow
: : );
: : 中 nCmdShow,MSDN中有这么段话:
: : This parameter is ignored the first time an application calls ShowWindow, if 
: : the program that launched the application provides a STARTUPINFO structure. 
: : Otherwise, the first time ShowWindow is called, the value should be the 
: : value obtained by the WinMain function in its nCmdShow parameter.
: : 
: : 要怎么理解???
: : 
: : 我的理解是,如果我用CreateProcess创建某程序,该程序就是创建个窗口,别无其他功
: : 能,调用CreateProcess时提供了STARTUPINFO si,并将相应的标志位设置si.dwFlags =
: (以下引言省略...)

-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 125.78.224.32]
CrLF
53453131364

本 文:[转寄][转贴][删除][修改][回复][作者:CrLF][人气:3]
发信人: CrLF (CrLF(落羽猫)), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月09日17:28:30 星期三), 站内信件 WWWPOST 

不不,你还是没明白我的意思。 

首先是,不一定是*第一次*调用ShowWindow~  而是第一次对符合主窗口条件(见上面) 
的窗口调用ShowWindow 的时候。 

这个时候如果你用SW_SHOW或SW_SHOWNORMAL,系统会替换。 

你的程序系统认为它是主窗口了,但是你给的是最大化,系统就不管了~ 

【 在 novice (Android) 的大作中提到: 】 
: 那意思是 ShowWindow第一次调用与后续调用没区别?
: 
: 【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】
: : 不是,我查给你的规则是实际的规则(系统实际是这样做的)。msdn文档写的含糊 :)
: : 
: : 信我查的好了。写msdn文档的人肯定没有写windows的人知道的清楚:P
: : 
: : 
: : (以下引言省略...)

-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 60.18.151.188]
novice
69307364
本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:5]
发信人: novice (Android), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月09日20:12:03 星期三), 站内信件 WWWPOST 

抱歉在这个问题上纠缠这么久。 

再说说我现在的理解。你的意思是:在满足主窗口条件时,第一次调用ShowWindow时使 
用SW_SHOW或SW_SHOWNORMAL,会使窗口按照STARTUPINFO的信息显示? 

MSDN里文档里说的“忽略”就是上述意思?“This parameter is ignored the first  
time an application calls ShowWindow, if the program that launched the  
application provides a STARTUPINFO structure.”感觉另有深意啊。 

那为什么要称为“ignored”呢? 因为是上述说法的话,那等同于在SW_SHOW或SW_ 
SHOWNORMAL时,使用STARTUPINFO的信息。而其他参数也按照各自本来的效果显示,并没 
有被忽略。 

感觉你的意思是在说明在什么条件下使用STARTUPINFO的信息,而我最大的疑惑是MSDN文 
档里的“忽略”二字。不对之处请指正。 

【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】 
: 不不,你还是没明白我的意思。
: 
: 首先是,不一定是*第一次*调用ShowWindow~  而是第一次对符合主窗口条件(见上面)
: 的窗口调用ShowWindow 的时候。
: 
: 这个时候如果你用SW_SHOW或SW_SHOWNORMAL,系统会替换。
: 
: 你的程序系统认为它是主窗口了,但是你给的是最大化,系统就不管了~
: 
: 【 在 novice (Android) 的大作中提到: 】
: : 那意思是 ShowWindow第一次调用与后续调用没区别?
: : 
-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 222.77.201.102] 
※ 修改:・novice 于 2011年02月09日20:25 修改本文・[FROM: 222.77.201.102]
CrLF
53453131364

本 文:[转寄][转贴][删除][修改][回复][作者:CrLF][人气:2]
发信人: CrLF (CrLF(落羽猫)), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月09日23:00:37 星期三), 站内信件 WWWPOST 

it is "ignored" becuase it is "overridden" :) 

MSDN只是没说识别的细节而已。实际上你从设计意图上理解比较好。它之所以这么设计 
,就是为了让写程序的人不用考虑到底该用什么参数。你只要主窗口的ShowWindow用 
WinMain参数里给定的那个,根本不用考虑这些。如果需要在前面显示对话框,就该是模 
态的。如果同时显示对话框,主窗口一般是所有者……总之,为了方便,你什么都不做 
,交给Windows就好。 

【 在 novice (Android) 的大作中提到: 】 
: 抱歉在这个问题上纠缠这么久。
: 
: 再说说我现在的理解。你的意思是:在满足主窗口条件时,第一次调用ShowWindow时使
: 用SW_SHOW或SW_SHOWNORMAL,会使窗口按照STARTUPINFO的信息显示?
: 
: MSDN里文档里说的“忽略”就是上述意思?“This parameter is ignored the first 
: time an application calls ShowWindow, if the program that launched the 
: application provides a STARTUPINFO structure.”感觉另有深意啊。
: 
: 那为什么要称为“ignored”呢? 因为是上述说法的话,那等同于在SW_SHOW或SW_
: SHOWNORMAL时,使用STARTUPINFO的信息。而其他参数也按照各自本来的效果显示,并没
: 有被忽略。
: 
: 感觉你的意思是在说明在什么条件下使用STARTUPINFO的信息,而我最大的疑惑是MSDN文
: 档里的“忽略”二字。不对之处请指正。
: 
: 【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】
: : 不不,你还是没明白我的意思。
: : 
: : 首先是,不一定是*第一次*调用ShowWindow~  而是第一次对符合主窗口条件(见上面)
: (以下引言省略...)
-- 
※ 来源:・瀚海星云 bbs.ustc.edu.cn・[FROM: 60.18.151.188] 
※ 修改:・CrLF 于 2011年02月09日23:08 修改本文・[FROM: 60.18.151.188]
novice
69307364
本 文:[转寄][转贴][删除][修改][回复][作者:novice][人气:0]
发信人: novice (Android), 信区: VC 
标  题: Re: ShowWindow 的疑问 
发信站: 瀚海星云 (2011年02月10日09:59:17 星期四), 站内信件 WWWPOST 

it is "ignored" becuase it is "overridden" 。了解了。 

哦哦,那结论是第一次调用时乖乖用WinMain的nCmdShow啦。 

多谢! 

【 在 CrLF (CrLF(落羽猫)) 的大作中提到: 】 
: it is "ignored" becuase it is "overridden" :)
: 
: MSDN只是没说识别的细节而已。实际上你从设计意图上理解比较好。它之所以这么设计
: ,就是为了让写程序的人不用考虑到底该用什么参数。你只要主窗口的ShowWindow用
: WinMain参数里给定的那个,根本不用考虑这些。如果需要在前面显示对话框,就该是模
: 态的。如果同时显示对话框,主窗口一般是所有者……总之,为了方便,你什么都不做
: ,交给Windows就好。
: 
: 【 在 novice (Android) 的大作中提到: 】
: : 抱歉在这个问题上纠缠这么久。
: : 
: : 再说说我现在的理解。你的意思是:在满足主窗口条件时,第一次调用ShowWindow时使
: : 用SW_SHOW或SW_SHOWNORMAL,会使窗口按照STARTUPINFO的信息显示?
: : 
: : MSDN里文档里说的“忽略”就是上述意思?“This parameter is ignored the first 
: : time an application calls ShowWindow, if the program that launched the 
: : application provides a STARTUPINFO structure.”感觉另有深意啊。
: : 
: : 那为什么要称为“ignored”呢? 因为是上述说法的话,那等同于在SW_SHOW或SW_
: : SHOWNORMAL时,使用STARTUPINFO的信息。而其他参数也按照各自本来的效果显示,并没
: (以下引言省略...)