2008年1月30日星期三

#include 和 #include

#include <cstring>
...
string theString="Hello";
cout<<string<<endl;

MSVC6.0 reports:
error C2679: binary '<<' : no operator defined which takes a right-hand operand of type 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >' (or there is no acceptable conversion)


BUT
#include <string>
string theString="Hello";
cout<<string<<endl;


is OK under MSVC6.0

2008年1月28日星期一

CANNOT ACCESS THE CLASS VIEW INFORMATION FILE.

CANNOT ACCESS THE CLASS VIEW INFORMATION FILE. CLASS VIEW INFORMATION WILL NOT BE AVAILABLE.


无法访问 ClassView 信息文件。 ClassView 信息将不可用。


1) Close Visual Studio. Check Task manager, close any MSDEV.exe. Reopen the workspace file.
or
2) Delete .clw or .ncb file. Open the workspace file and let them be rebuilt.

2008年1月24日星期四

拷贝构造函数的相关内容(浅拷贝,深拷贝,赋值运算符)

Copy constructor is
  • a constructor function with the same name as the class
  • used to make deep copy of objects.
拷贝构造函数(或者叫复制构造函数)是与构造函数同名的函数,它来实现对象的深拷贝。
什么是深拷贝和浅拷贝?浅拷贝复制的是对象的所有成员的值,对于指针,它只复制指针,而不会复制其指向的动态分配的内存。默认的拷贝构造函数和赋值运算符实现的是浅拷贝。浅拷贝的问题是,如果存在多个指针指向同一处内存,而这段内存在某个时候由于一个对象的结束而被释放,那么其他对象的指针就指向了无效的内存区域!
深拷贝必须通过自己编写拷贝构造函数和重载赋值运算符来实现,它将动态分配的内存也实现拷贝。

There are 3 important places where a copy constructor is called.
  • When an object is created from another object of the same type
  • When an object is passed by value as a parameter to a function
  • When an object is returned from a function
拷贝构造函数主要在下述的三种情况下被调用:
  • 当从另一个同类型的对象中创建对象时

Person q("Mickey"); // constructor is used to build q. no copy constructor
Person r(p); // copy constructor is used to build r.
Person p = q; // copy constructor is used to initialize in declaration.
p = q; // Assignment operator, no constructor or copy constructor
  • 当对象作为一个函数的参数用值传递的方式传递时。

f(p); // copy constructor initializes formal value parameter.

  • 当对象被函数用作返回值返回时。
当对象间赋值的时候,不会调用拷贝构造函数,这时候使用的是赋值运算符,请查看文末的说明。
If a copy constructor is not defined in a class, the compiler itself defines one. This will ensure a shallow copy. If the class does not have pointer variables with dynamically allocated memory, then one need not worry about defining a copy constructor. It can be left to the compiler's discretion.
But if the class has pointer variables and has some dynamic memory allocations, then it is a must to have a copy constructor.
如果不在类中定义拷贝构造函数,编译器会自动定义一个,完成浅拷贝。如果类中没有指针变量指向动态分配的内存,浅拷贝就OK,那么就没有必要自定义拷贝构造函数
如果有,必须进行深拷贝的话,则必须定义拷贝构造函数

If you need a copy constructor, you also need a destructor and operator=
如果需要一个拷贝构造函数,那么你同样需要一个析构函数和对赋值运算符=的重载。

例如:
class A //Without copy constructor
{
private:
int x;
public:
A() {x = 10;}
~A() {}
}
class B //With copy constructor
{
private:
char *name;
public:
B()
{
name = new char[20];
}
~B()
{
delete name[];
}
//Copy constructor
//拷贝构造函数的参数必须为const,这样可以防止原来的对象被破坏,同时,它必须是引用,因为如果不是引用而用值传递,那么就需要拷贝,就需要调用拷贝构造函数,就需要拷贝,就需要.....
B(const B &b)
{
name = new char[20];
strcpy(name, b.name);
}
};

Let us Imagine if you don't have a copy constructor for the class B. At the first place, if an object is created from some existing object, we cannot be sure that the memory is allocated. Also, if the memory is deleted in destructor, the delete operator might be called twice for the same memory location.
设想没有为B类定义拷贝构造函数,首先,如果新的对象通过一个已经存在的对象来创建,那么我们不能肯定内存被正确地分配了。并且,内存被析构函数删除,同一处内存可能会被删除两次。
Difference between copy constructor and assignment
拷贝构造函数和赋值的区别
A copy constructor is used to initialize a newly declared variable from an existing variable. This makes a deep copy like assignment, but it is somewhat simpler:
  • There is no need to test to see if it is being initialized from itself.
  • There is no need to clean up (eg, delete) an existing value (there is none).
  • A reference to itself is not returned.
拷贝构造函数从一个已经存在的变量来初始化一个新声明的变量。这使得深拷贝和赋值有些相像。但是更简单:
首先,不需要像赋值运算那样检查是否从自己初始化
其次,不需要清除现有的值(因为是新创建,所以没有现有值)
最后,没有返回值。

赋值运算符的定义如下:
The following steps are a typical for the assignment operator.
  1. No self-assignment. Test to make sure you aren't assigning an object to itself, eg x = x. Of course no one would write that statement, but in can happen when one side of the assignment is not so obviously the same object. Self assignment fails because the memory associated with the current value of the left-hand-side is deallocated before the assignment, which would invalidate using it from the right-hand-side.
  2. Delete the associated memory. Same as copy constructor.
  3. Copy all the members. Same as copy constructor.
  4. Return *this. This is necessary to allow multiple assignment, eg x = y = z;

//--- file Person.h
. . .
class Person {
private:
char* _name;
int _id;
public:
Person& Person::operator=(const Person& p);
. . .
}
//--- file Person.cpp
. . .
//=================================================== operator=
Person& Person::operator=(const Person& p) {
if (this != &p) { // make sure not same object
delete [] _name; // Delete old name's memory.
_name = new char[strlen(p._name)+1]; // Get new space
strcpy(_name, p._name); // Copy new name
_id = p._id; // Copy id
}
return *this; // Return ref for multiple assignment
}//end operator=

如果存在基类,那么在重载赋值运算符时,也必须调用基类的赋值运算符
//--- file Parent.h
class Parent {...}; // declaration of base class
//--- file Child.h
#include "Parent.h"
class Child : public Parent { // declaration of derived class
public:
Child& Child::operator=(const Child& source);
};//end class Child
//--- file Child.cpp
#include "Child.h"
Child& Child::operator=(const Child& source) {
if (this != &source) {
this->Parent::operator=(source);
. . . // copy all our own fields here.
}
return *this;
}//end operator=
其他:
为了防止拷贝和值传递等方式对对象进行错误的赋值,可以将拷贝构造函数定义为私有,并且并不实现她,对赋值运算符也一样。

参考文献:
http://www.codersource.net/cpp_copy_constructors.html
http://www.fredosaurus.com/notes-cpp/oop-condestructors/copyconstructors.html
http://www.fredosaurus.com/notes-cpp/oop-overloading/overloadassign.html
http://cse.stanford.edu/class/cs193d/handouts/14CopyConstructors.pdf

下面的函数可能有什么样的运行时错误?

string &func(){
string str;
while(cin>>str){
}
return str;
}

直接在VC6.0中编译,给出的错误是
warning C4172: returning address of local variable or temporary

Compiler Warning (level 1) C4172:returning address of local variable or temporary

A function returned the address of a local variable or a temporary. Local variables and temporaries are destroyed when a function returns; consequently the address returned will almost certainly be invalid.

返回局部变量的地址或者临时变量。因为二者在函数返回时就会销毁,所以返回的地址几乎肯定是无效的。

When returning the address of a variable, you should return the address of a global variable or a dynamically allocated variable, which will continue to exist after the function ends.

应该返回全局变量或者动态分配的变量,这样的变量会在函数结束后依然存在。

这里的while(cin>>str){}并不要求输入任何东西即返回。
而if(cin>>str){printf("I will not be printed");}else{printf("I will be printed!")}

Passing By Reference-to-const 通过对常量的引用来传递参数

Passing By Reference-to-const

By Dan Saks
Embedded Systems Design
(10/01/01, 09:13:58 H EDT)


The rules for initializing references make passing by reference-to-const an efficient and attractive alternative to passing by value.
引用的初始化机制使得通过对常量的引用来传递参数比按值传递更高效。

As in C, function calls in C++ normally pass arguments by value. For example, given:
和在C语言中一样,函数通常通过值来传递参数。如:

int abs(int i);
int n;


calling abs(n) passes argument n to function abs by value. That is, the program copies the value of n to abs's parameter i each time it makes this call.
C++ uses pass-by-value even for objects of class types. (In C++, class types include struct and union types.) For example, given some struct type:
C++还能够通过按值传递的方式传递类类型的数据(包括结构和共同体)。
struct gadget
{
// a whole bunch of fields
};


and:


int test(gadget g);
gadget x;


calling test(x) passes argument x by value. Much as before, the program copies x's value to parameter g each time it makes this call.
程序每次调用都需要拷贝x的值。
For large struct objects, passing by value can be very slow because it copies each byte of the argument to the corresponding byte of the parameter, as if by calling the Standard C memcpy function. The program does not necessarily call memcpy to do the job, but the argument passing mechanism behaves as if it did. Strictly speaking, passing a class object by value in C++ conceptually calls a special function associated with the class called the copy constructor. However, when the class is just a struct as in C, the copy constructor behaves essentially like memcpy.
对于较大的结构对象,按值传递方式速度非常慢。通过值传递的方式传递一个类对象,在C++中调用了类的拷贝构造函数。对于结构对象,拷贝构造函数的表现与memcpy一样(非常耗时)。

You can avoid the cost of copying a large argument by passing it by address rather than by value. You simply change the function declaration to:
可以通过使用按地址传递的方式来避免这种消耗大量资源的方式,如:

int test(gadget *g);


and then change the function call to test(&x). Passing &x (the address of x) is often a lot less work than passing an entire copy of x.
函数调用的时将地址传递给函数,因而可以节省参数传递的时间。

Unfortunately, when you change the parameter type from gadget to "pointer to gadget," you introduce a change in the function's behavior, or at least the possibility of a change. When passing by value, the function only sees a copy of the original gadget, so it cannot change that gadget. In my example, when passing by value, calling test(x) cannot change x. When passing by address, the function can dereference its pointer parameter and store new values into the gadget argument. That is, calling test(&x) might change x. Of course, you can prevent the function from tampering with its argument by using the const qualifier, as in:
通过值传递时,函数只得到了参数的一个拷贝,函数无法改变参数的值。
通过引用传递值时,可以放弃指针指向的参数而存入新的参数,也就是说 test(&x)可以改变x的值。当然,你可以通过添加const 修饰符来避免参数被修改。

int test(gadget const *g); //注意const的位置,这和const gadget是否一样呢?


For very large objects, passing by address (with const) is almost always faster than passing by value. For objects of modest size (on the order of eight to 16 bytes), it isn't always clear at the outset whether passing by address will actually be faster than passing by value. It depends on the target machine's architecture and what the function does with the parameter. Sometimes you just have to make your best guess and wait to measure the performance of the running program. If it turns out that you guessed wrong, you may have to rewrite the function.
当传递的对象较大时,按值传递参数肯定速度较慢。而对象速度较小时,速度则由计算机的结构决定,需要测试来确定。

Unfortunately, rewriting a function call so that it uses pass-by-address instead of pass-by-value, or vice versa, can be a bona fide maintenance headache. Changing the function declaration from:


int test(gadget g);


to:


int test(gadget const *g);


isn't much fuss, nor is changing the corresponding function definition. But numerous function calls might be scattered throughout the code, and you have to rewrite all those calls. In some cases, a call such as text(x) becomes test(&x). In others, test(*p) becomes test(p) (where p is a "pointer to gadget").
如果需要吧某个函数由按值传递改为按引用传递,对散布在代码中的众多的函数调用来说,非常麻烦。

In C++, passing by reference offers an alternative to passing by address. You can declare the test function as:
在C++中,有一种替代的方式:按地址传递,可以如下声明函数:

int test(gadget const &g);


In this case, parameter g has type "reference to const gadget." This lets you write the call as test(x), as if it were passing by value, but it yields the exact same performance as if it were passing by address. Again, the const qualifier prevents the function from changing the value of its actual gadget argument.
这样参数g的类型为“指向常量gadget的引用”。这样你就可以像传递值那样将函数调用写成test(x).

Changing a function parameter from passing by value to passing by reference-to-const is a fairly minor change. You must change the function's definition and corresponding declaration, if any, appearing in a header. Although you must recompile any code that calls the function, you need not rewrite the calls.


In short, passing by reference-to-const is a potentially efficient alternative to passing by value. To the calling function, an argument passed by reference-to-const looks and acts just like one passed by value. The argument expression in the call looks the same either way-you need not add or remove *s or &s when switching from one form to the other.
两种方式并不需要修改函数调用时的变量为*s或者&s;

When passing by value, the called function can't store into the actual argument because it only has access to a copy. When passing by reference-to-const, the called function can't store into the actual argument because it's const.
对于通过指向常量的引用和值传递两种方式,参数都不会被改变。

Dan Saks is the president of Saks & Associates, a C/C++ training and consulting company. He is also a consulting editor for the C/C++ Users Journal. You can write to him at dsaks@wittenberg.edu.

2008年1月22日星期二

#pragma 预处理指令

http://blog.csdn.net/freedomstar/archive/2007/11/01/1861565.aspx

在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为: #Pragma Para
其中Para 为参数,下面来看一些常用的参数。

(1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗
口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
#Pragma message(“消息文本”)
当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法
#ifdef _X86
#Pragma message(“_X86 macro activated!”)
#endif
当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_
X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了


(2)另一个使用得比较多的pragma参数是code_seg。格式如:
#pragma code_seg( ["section-name"[,"section-class"] ] )
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

(3)#pragma once (比较常用)
只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。

(4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

(5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体
外观的定义。

(6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等价于:
#pragma warning(disable:4507 34) // 不显示4507和34号警告信息
#pragma warning(once:4385) // 4385号警告信息仅报告一次
#pragma warning(error:164) // 把164号警告信息作为一个错误。
同时这个pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
这里n代表一个警告等级(1---4)。
#pragma warning( push )保存所有警告信息的现有的警告状态。
#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。
#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的一切改动取消。例如:
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。
(7)pragma comment(...)
该指令将一个注释记录放入一个对象文件或可执行文件中。
常用的lib关键字,可以帮我们连入一个库文件。


每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能:
#pragma loop_opt(on) // 激活
#pragma loop_opt(off) // 终止
有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,如“Parameter xxx is never used in function xxx”,可以这样:
#pragma warn —100 // Turn off the warning message for warning #100
int insert_record(REC *r)
{ /* function body */ }
#pragma warn +100 // Turn the warning message for warning #100 back on
函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。
每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。

用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为:

  #pragma data_seg ("shareddata")

  HWND sharedwnd=NULL;//共享数据

  #pragma data_seg()

1,#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的,有名字的数据段。最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享DLL中的全局变量。

2,共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。

3。如果在一个DLL中这么写:

#pragma data_seg("MyData")

int g_Value; // Note that the global is not initialized.

#pragma data_seg()

DLL提供两个接口函数:

int GetValue()
{
return g_Value;
}

void SetValue(int n)
{
g_Value = n;
}

然 后启动两个进程A和B,A和B都调用了这个DLL,假如A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值不一定是5,而是一个未定义的值。因为DLL中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。假如你对g_Value进行了初 始化,那么g_Value就一定会被放进MyData段中。换句话说,如果A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值就一定是5!这就实现了跨进程之间的数据通信!
VC6常用编译指令
1.编译时打印字符串
#if __DEGUB
#pragma message( "Debug" )
#endif
2.忽略某个warning
编译期
#pragma warning(disable:4800)
....
#pragma warning(default:4800)
连接期
#pragma comment(linker,"/ignore:4078")
3.定义段名称
#pragma data_seg("segment-name")
#pragma code_seg("segment-name")
#pragma const_seg("segment-name")
#pragma bss_seg("segment-name")

4.定义为进程共享段
#pragma data_seg("name");
...
#pragma data_seg();
#pragma comment(linker,"/section:name,RWS")
5.合并code和代码段
#pragma comment(linker, "/MERGE:.text=.data")

6.导入lib
#pragma comment (lib, "shlwapi.lib")
7.内存对齐
#pragma pack(2)
#pragma pack()
简要记录sizeof和内存对齐
本来,一般是不自己计算sizeof的,知道内存对齐会对sizeof有影响,所以从来不手算,而是代码里写上sizeof。今天又看到http://blog.vckbase.com/smileonce/archive/2005/08/08/10658.html,翻来了http://blog.vckbase.com/billdavid/archive/2004/06/23/509.html ,自己想想还是也记录一下,万一以后自己真的也要计算sizeof,忘了,还能有个提示,也给不是很明白的朋友一个参考。
struct sample1
{
char a; /// sizeof(char) = 1
double b; /// sizeof(double) = 8
};
///default( 缺省#pragam pack(8) ——VC6和VC71,其它编译器,个人未知 )
///1+8 = 9 —> 16( 8 <>

#pragma pack( 4 )
///1+8 = 9 —> 12( 8 <>

#pragma pack( 2 )
///1+8 = 9 —> 10( 8 <>

#pragma pack( 1 )
///1+8 = 9 —> 9

#pragma pack( 16 )
///1+8 = 9 —> 16( 16—>8 ---- 8 <>

struct sample2
{
char a; ///1
int b; ///4
};
#pragma pack( 8 )
/// 1 + 4 = 5 —> 8( 8 —> 4 )

#pragma pack( 16 )
/// 1 + 4 = 5 —> 8( 16 —> 4 )

说明:#pragma pack告诉编译器进行内存边界对齐,一般都是采用编译器的设置对整个项目采用同一对齐方案,而且通常为缺省8字节对齐。

/////////////////////////////////以下内容于 2005-12-10 添加/////////////////////////////////


今天又看到以前测试的一段代码,突然不明白了起来,又稍写了几个测试。
struct sample3
{
char a; ///1
int b; ///4
char c; ///1
};
///default ///12
#pragma pack( 4 ) ///12
#pragma pack( 2 ) ///08
#pragma pack( 1 ) ///06
#pragma pack( 16 ) ///12

原来,其实编译器,根据对齐指示的对齐字节和最大成员的字节,对每个成员进行了对齐:编译器会取对齐指示和最大成员字节中较小的一个用于补齐其它成员。那么,上面的sample1/2/3也就都在情理之中了。为了证实这点,我们还再看一个例子:
struct sample4
{
char a; ///1
int b; ///4
double c; ///8
char d; ///1
};
///default: ///8+8+8+8 = 32
#pragma pack( 4 ) ///4+4+8+4 = 20
#pragma pack( 2 ) ///2+4+8+2 = 16
#pragma pack( 1 ) ///1+4+8+1 = 14
#pragma pack( 16 ) ///8+8+8+8 = 32
而实际上,编译器给出的值是:24、20、16、14、24
那么说明我错了。注意一下,我发现char a,int b加起来也才5<8,难到编译器进行了联合对齐?
struct sample5
{
char a; ///1
double c; ///8
int b; ///4
char d; ///1
};
编译器给出结果:24、20、16、14、24

这用联合对齐的解释正好符合,我又试验了不同的数据,发现这个结论并不太准确确。于是,我输出了每一个对象成员地址进行分析。由于试验数据量很大,这里就不列出了。

最后得到了以下结论:
1. 成员的对齐是按声明顺序进行的;
2. 对齐值由编译指示和最大成员两者较小的值决定;
3. 未对齐到对齐值的成员一起形成块对齐(联合对齐);
4. 上一个(下一个)对齐采用自己较大则不变,自己较小则填充自己对齐到上一个(下一个)大小;
5. 每成员对齐:如果前面已对齐到对齐值,下一个对齐自己。如果前面未对齐到对齐值,如果加上下一个成员不大于对齐值,下一个对齐自己,否则填充自己块对齐到对齐值。
6. 最后还未对齐到对齐值的,填充空间块对齐到对齐值。

从这些结论,可以得到:
1. 以上的对齐原则其实是尽量整齐排列、尽量节省内存。
2. 声明成员应该尽量避免不同类型错杂开来,最好采用从小到大或者从大到小的顺序(错开后,会因为上对齐和下对齐而增加填充开销)。
3. 编译器缺省采用8字节对齐主要是因为最大基本类型为8自己(以前自己不明白,在论坛提过问,后来,以为是SSE指令的原因)。
4. 手算sizeof是没有必要的,负责的(可以先对齐出对齐块,用块数乘对齐值)。
pragma的作用
不 同的主机和操作系统都有其特点。为了利用好这些特点,c和c++的编译器必须能够针对不同的特性进行处理。比方说,有些程序需要准确地对内存进行管理(如 应当将数据存放到哪里)或者需要指定函数接受参数的方式。#pragma指示器便用于此处!通过#pragma,我们的c和c++程序即可以保证兼容性也 可以利用到低层系统的特色!
语法规则: #pragma token-string 其中token-string给出了特定的编译指令和参数。
利用条件申明,pragma可以提供预处理功能和对编译器进行定制。c和c++可以识别以下pragma:
alloc_text comment init_seg1 optimize
auto_inline component inline_depth pack
bss_seg data_seg inline_recursion pointers_to_members1
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp1
const_seg include_alias once warning

以下我们便就一些重要的pragma进行探讨:
#pragma comment(将注释放置到生成的目标文件或者可执行文件中去。commet-type一共有5种类型。可选的参数commenstring为这5种类型中的个别类型提供额外的参数。以下我们就5种类型进行分析与介绍:
compiler:将编译器名字和版本号放如目标文件。
exestr:将commentstring放到目标文件里面。
lib:将查找库的信息放如目标文件里面。此时,必须使用commentstring参数,用于记录lib的名字,最好还包括路径。
#pragma comment( lib, "emapi" )首先在当前目录底下查找emapi.lib,然后在lib环境变量的路径里面寻找
linker:将linker option放入目标文件里面。通过注释类型确定linker的选项,从而避免在Setting对话框里面进行设置。比如:
#pragma comment(linker, "/include:__mySymbol")
user:将一般的注释放入到目标文件里面。
#pragma optimize( ":在函数一级对进行优化。该语句必须出现在函数外面,并且只会对该声明后的第一个函数有作用。on或者off确定是否起作用。 [optimization-list]", {on | off} ) comment-type [, commentstring] )
Parameter(s) Type of optimization
a Assume no aliasing.
g Enable global optimizations.
p Improve floating-point consistency.
s or t Specify short or fast sequences of machine code.
w Assume no aliasing across function calls.
y Generate frame pointers on the program stack.

由于比较简单,上面的英语我就不介绍了!!!调用可以是下面的形式:#pragma optimize( "atp", on )
#pragma function( function1 [, function2, ...] ) #pragma intrinsic( function1 [, function2, ...] )以上两个声明确定了所选函数的调用类型。如果有一函数名出现在function的参数里面,则说明以一般函数的形式调用。如果出现在了 intrinsic里面则编译器在编译的时候将函数代码转化了inline代码。
#pragma data_seg( ["section-name"[, "section-class"] ] ):为数据指定默认的存储区。如:
#pragma data_seg( "MY_DATA" )。这句声明将使得在#pramga后申明的数据将在名为MY_DATA存储区里面进行分配。
先介绍到此,告一段落。以后遇到了问题,再来添加!!!
struct 关于sizeof的大小问题
typedef struct tagSocketData {
BYTE nSize;
BYTE nType;
DWORD nDataSize;
DWORD nIndex;
SOCKET socket;
DWORD nDataLength;
} SOCKETDATA, *LPSOCKETDATA;

SOCKETDATA sd;
sd.nSize = sizeof(SOCKETDATA); //本来应该是18, 可却是20

sizeof(SOCKETDATA) = 20, 本来是18字节的大小
实际大小却是20
可存为文件的时候却是按照18字节的大小存储

应该怎么解决??


---------------------------------------------------------------

看看这个

struct tagHDD
{
char c1;
DWORD n;
}HDD;
long n=sizeof(HDD);//n会返回8,为什么,真怪。

回复人: bluebohe(薄荷)
这不怪,就怪在缺省的对齐方式上。
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。

例如,下面的结构各成员空间分配情况。

struct test {
char x1;
short x2;
float x3;
char x4;
};
   结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间 填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4 字节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间 为12字节。
现在你知道怎么回事了吧?
更改C编译器的缺省分配策略
  一般地,可以通过下面的方法改变缺省的对界条件:
  ? 使用伪指令#pragma pack ([n])
  #pragma pack ([n])伪指令允许你选择编译器为数据分配空间所采取的对界策略。
例如,在使用了#pragma pack (1)伪指令后,test结构各成员的空间分配情况就是按照一个字节对齐了,格式如下:
#pragma pack(push) //保存对齐状态
#pragma pack(1)
//定义你的结构
//…………
#pragma pack(pop)

---------------------------------------------------------------

在 编译选项中可以设置:菜单中“工程”-->“设置”, 弹出一个“project setting”对话框。然后选择“C/C++”标签--->在“Y分类”中选择“Code Generation”--->在“Struct member alignment”中选择“1 Byte”。

重新编译。ok了!!
---------------------------------------------------------------

#pragma pack(push,1)
typedef struct tagSocketData {
BYTE nSize;
BYTE nType;
DWORD nDataSize;
DWORD nIndex;
SOCKET socket;
DWORD nDataLength;
} SOCKETDATA, *LPSOCKETDATA;
#progma pack(pop,1)

就可以了~
内存对齐
从计算结构变量字节大小的问题开始
问题:

在32位编译系统中,
typedef struct
{
int A
char B
}T_s;
请问T_s的长度为几个字节?
答案:

题目不够严谨,跟编译器和编译选项有关的。
pc上的32位编译器一般缺省是4位对齐,所以长度会是8,此时在B后填充3字节,但对齐方式可以改的;
而有些嵌入系统的编译器缺省是不对齐的,所以长度为5。

比如在vc中,
如果
#pragma pack(4) //缺省
则sizeof(T_s)等于8
如果
#pragma pack
则sizeof(T_s)等于5
而且和cpu有关,在有的机器上int不一定就是32位

要因结构对齐而定,对齐方式可以是1, 2, 4, 8, or 16
1对齐:5;2对齐:6;4对齐:8;8对齐:8;16对齐:8

char 是8位的,结构长度是8字节,在B之前没有对齐被位,但在B之后要补3个字节以便于在数组中把下一个元素的A对齐到4字节边界,当然这都是一般编译器在4 字节对齐的情况下,如果某一编译器偏不这样实现,你也不能说它错了。因此如果我写一个编译器就把它的长度设为6字节,那么说它是6字节也正确。其实字节对 齐的知识对编写代码并没有什么帮助,并且也不应该利用这些知识。我以前曾经说过正确的态度是“不假设没有进行字节对齐,不假设编译时的对齐方式(包括可以 不进行对齐)”。


计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以 参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
看一个例子:
将A写入二进制文件
#pragma pack (1)
struct A
{
char a;
int b;
};
文件
61 06 00 00 00
#pragma pack (2)
struct A
{
char a;
int b;
};
文件
61 CC 06 00 00 00
#pragma pack (4)
struct A
{
char a;
int b;
};
文件
61 CC CC CC 06 00 00 00
#pragma pack (4)
struct A
{
char a;
int b;
};
文件
61 CC CC CC 06 00 00 00
#pragma pack (8)
struct A
{
char a;
int b;
};
文件
61 CC CC CC 06 00 00 00
该例子作者得出的结论:
结论是 实际的对齐长度 = [pack指定的对齐长度]和[struct中最长成员的长度]较小的一个。
[C] 结构对齐
http://community.csdn.net/Expert/FAQ/FAQ_Index.asp?id=182474

在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间

例如,下面的结构各成员空间分配情况

struct test
{
char x1;
short x2;
float x3;
char x4;
};
                 
   结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间 填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4 字节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间 为12字节。

更改C编译器的缺省分配策略
  一般地,可以通过下面的两种方法改变缺省的对界条件:
  · 使用伪指令#pragma pack ([n])
  · 在编译时使用命令行参数
#pragma pack ([n])伪指令允许你选择编译器为数据分配空间所采取的对界策略:

  
例如,在使用了#pragma pack (1)伪指令后,test结构各成员的空间分配情况就是按照一个字节对齐了

#pragma pack(push) //保存对齐状态
#pragma pack(1)
#pragma pack(pop)

编译器默认都是8字节对齐;


=============================================================================

http://data.gameres.com/message.asp?TopicID=13636

什么是内存对齐
考虑下面的结构:
struct foo
{
char c1;
short s;
char c2;
int i;
};

假设这个结构的成员在内存中是紧凑排列的,假设c1的地址是0,那么s的地址就应该是1,c2的地址就是3,i的地址就是4。也就是
c1 00000000, s 00000001, c2 00000003, i 00000004。
可是,我们在Visual c/c++ 6中写一个简单的程序:
struct foo a;
printf("c1 %p, s %p, c2 %p, i %p\n",
(unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
运行,输出:
c1 00000000, s 00000002, c2 00000004, i 00000008。
为什么会这样?这就是内存对齐而导致的问题。
为什么会有内存对齐
以下内容节选自《Intel Architecture 32 Manual》。
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某 些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整 除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
编译器对内存对齐的处理
缺省情况下,c/c++编译器默认将结构、栈中的成员数据进行内存对齐。因此,上面的程序输出就变成了:
c1 00000000, s 00000002, c2 00000004, i 00000008。
编译器将未对齐的成员向后移,将每一个都成员对齐到自然边界上,从而也导致了整个结构的尺寸变大。尽管会牺牲一点空间(成员之间有空洞),但提高了性能。
也正是这个原因,我们不可以断言sizeof(foo) == 8。在这个例子中,sizeof(foo) == 12。
如何避免内存对齐的影响
那么,能不能既达到提高性能的目的,又能节约一点空间呢?有一点小技巧可以使用。比如我们可以将上面的结构改成:
struct bar
{
char c1;
char c2;
short s;
int i;
};
这样一来,每个成员都对齐在其自然边界上,从而避免了编译器自动对齐。在这个例子中,sizeof(bar) == 8。
这个技巧有一个重要的作用,尤其是这个结构作为API的一部分提供给第三方开发使用的时候。第三方开发者可能将编译器的默认对齐选项改变,从而造成这个结构在你的发行的DLL中使用某种对齐方式,而在第三方开发者哪里却使用另外一种对齐方式。这将会导致重大问题。
比如,foo结构,我们的DLL使用默认对齐选项,对齐为
c1 00000000, s 00000002, c2 00000004, i 00000008,同时sizeof(foo) == 12。
而第三方将对齐选项关闭,导致
c1 00000000, s 00000001, c2 00000003, i 00000004,同时sizeof(foo) == 8。
如何使用c/c++中的对齐选项
vc6中的编译选项有 /Zp[1|2|4|8|16] ,/Zp1表示以1字节边界对齐,相应的,/Zpn表示以n字节边界对齐。n字节边界对齐的意思是说,一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上,取它们中的最小值。也就是:
min ( sizeof ( member ), n)
实际上,1字节边界对齐也就表示了结构成员之间没有空洞。
/Zpn选项是应用于整个工程的,影响所有的参与编译的结构。
要使用这个选项,可以在vc6中打开工程属性页,c/c++页,选择Code Generation分类,在Struct member alignment可以选择。
要专门针对某些结构定义使用对齐选项,可以使用#pragma pack编译指令。指令语法如下:
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )
意义和/Zpn选项相同。比如:
#pragma pack(1)
struct foo_pack
{
char c1;
short s;
char c2;
int i;
};
#pragma pack()
栈内存对齐
我们可以观察到,在vc6中栈的对齐方式不受结构成员对齐选项的影响。(本来就是两码事)。它总是保持对齐,而且对齐在4字节边界上。
验证代码
#include
struct foo
{
char c1;
short s;
char c2;
int i;
};
struct bar
{
char c1;
char c2;
short s;
int i;
};
#pragma pack(1)
struct foo_pack
{
char c1;
short s;
char c2;
int i;
};
#pragma pack()

int main(int argc, char* argv[])
{
char c1;
short s;
char c2;
int i;
struct foo a;
struct bar b;
struct foo_pack p;
printf("stack c1 %p, s %p, c2 %p, i %p\n",
(unsigned int)(void*)&c1 - (unsigned int)(void*)&i,
(unsigned int)(void*)&s - (unsigned int)(void*)&i,
(unsigned int)(void*)&c2 - (unsigned int)(void*)&i,
(unsigned int)(void*)&i - (unsigned int)(void*)&i);
printf("struct foo c1 %p, s %p, c2 %p, i %p\n",
(unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
(unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
printf("struct bar c1 %p, c2 %p, s %p, i %p\n",
(unsigned int)(void*)&b.c1 - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.c2 - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.s - (unsigned int)(void*)&b,
(unsigned int)(void*)&b.i - (unsigned int)(void*)&b);
printf("struct foo_pack c1 %p, s %p, c2 %p, i %p\n",
(unsigned int)(void*)&p.c1 - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.s - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.c2 - (unsigned int)(void*)&p,
(unsigned int)(void*)&p.i - (unsigned int)(void*)&p);
printf("sizeof foo is %d\n", sizeof(foo));
printf("sizeof bar is %d\n", sizeof(bar));
printf("sizeof foo_pack is %d\n", sizeof(foo_pack));

return 0;
}

VC中预处理指令的详解
在 所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为: #Pragma Para
其中Para 为参数,下面来看一些常用的参数。

(1)message 参数。
Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
#Pragma message(“消息文本”)
当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法
#ifdef _X86
#Pragma message(“_X86 macro activated!”)
#endif
当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_
X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。

(2)另一个使用得比较多的pragma参数是code_seg。
格式如:
#pragma code_seg( ["section-name"[,"section-class"] ] )
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

(3)#pragma once (比较常用)
只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。

(4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。
BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

(5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体
外观的定义。

(6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )
等价于:
#pragma warning(disable:4507 34) // 不显示4507和34号警告信息
#pragma warning(once:4385) // 4385号警告信息仅报告一次
#pragma warning(error:164) // 把164号警告信息作为一个错误。
同时这个pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1861565

2008年1月19日星期六

Design a Logo - The Ultimate Guide LOGO 设计终极指南

http://www.youthedesigner.com/2008/01/11/design-a-logo-the-ultimate-guide/

Written by Gino Orlandi, Edited by Jessica Stockdale

Logo design is arguably one of the most important and valued areas of design. A quality logo design combined with the branding of an organization or company can become one of the most powerful forces in today’s society. If you love logo design as much as I do, then I am sure you will enjoy these logo design tips and resources.

LOGO设计很重要,下面的内容也很重要。

LOGO DESIGN TIPS

Concepts, Concepts, Concepts! 概念,创意!

I like to believe there’s a perfect concept out there for every project, but the hard part is finding it - or at least something close to it. The only way to do this is to brainstorm like crazy. Start looking up competitors, do Google image searches, write down keywords, do some mind mapping, and make sure you put everything down on paper! You don’t want to come up with a great idea only to forget it the next morning.

头脑风暴,拼命想!可以参考竞争者的LOGO,写些关键字到Google Image中搜索一下。有什么点子一定要写下来。

Nothing like Sketching 草图无以替代

A lot of designers like to go straight to the computer, but the power of sketching is often underestimated. You can quickly sketch out multiple concepts and create variations to see what works and what doesn’t - in a matter of minutes. The computer will slow you down so be sure to break out the sketch pad, colored pencils, markers or whatever you prefer - and start sketching away.

Did you know? Large design companies will often sketch out dozens of pages of logo concepts before they even touch a computer mouse. Take a tip from the pros and focus on your sketches at first.

先在纸上画草图,不要急着碰电脑,那东西慢!

Research the End Requirements 研究客户需求

It’s always a good idea to talk to your client at the start to see what they plan on doing with the logo. Ask them if it going to just be on stationary or is it going to be on billboards and banners and such. This can help you better fine tune the logo for them to make sure it will look right in multiple instances.

跟客户谈谈这个LOGO的功能,要印在什么地方等等

Use the Most Professional Program 用最专业的软件

Although it can be tempting to use a program like Adobe Photoshop to design logos when starting out, mastering Adobe Illustrator and its pen tool will be essential if you are serious about logo design. Adobe Illustrator has a vector format that will allow your logo to be scaled up and down with no loss of quality.

比如 Adobe Illustrator

Keep it Simple 尽量简单

In general it’s better to keep logo design simple. The main idea behind this is that you want the logo to be able to hold up well at very tiny sizes. A good test is to create a 16×16 pixel “favicon” of the logo and see how it looks. This is the smallest size the logo will probably ever be in.

简单了即使缩小了也看得过去。

Test it at Varying Sizes 试验不同的大小

Similar to the above mentioned, you should physically test the logo yourself by printing it in varying sizes. Also take a look at the logo from different distances to see how it would look on a poster, or on a t-shirt and stationary.

试验不同尺寸的LOGO以及从不同距离观察,放在T恤和文具上的效果。

Test it in Multiple Colors 试验不同色调

Clients always have different needs and different budgets and a quality logo design will be able to adapt to these circumstances and still look great. Test the logo in a variety of color printing processes, such as one-color, two-color, four-color and so on.

好的LOGO换了颜色看上去仍然酷。试验一下单色、双色、多色调等等方案。

Test with Surrounding Text 加上环绕文字试试

Logos will rarely be seen totally alone, most of the time they will have taglines or other text nearby. So, why not test the logo ahead of time and see how it looks in different situations? Add a temporary tagline and see where it looks best. Justify the logo and text to the left, to the right, center it, and try out any other combinations of text and sizes.

试验将LOGO放在文字中间的效果,不同的位置和字体。LOGO不是总是单枪匹马。

MORE LOGO DESIGN TIPS

5 Vital Logo Design Tips

Branding Basics Create a Great Logo and Tag Line

LogoBee’s Top 10 Logo Design Tips

Paul Rand: Thoughts and Despair on Logo Design

Paul Rand – Corporate Identity Designs, Innovation and Excellence

WIKIPEDIA MUST READS LOGO设计名人

Below are some important people who helped shape identity design and typography as we know it. There are many more influential people who could be listed here, but these happen to be some of my favorites!

Paul Rand | William Caslon | Wally Olins | Aldus Manutius | Giambattista Bodoni | Max Miedinger

LOGO DESIGN INSPIRATION LOGO设计灵感

If you need some inspiration for your logo design and identity design projects then check out these websites which will be sure to jump start your creative engine. Simply click the images below.

Logopond

Logosauce

Faveup

LOGO DESIGN STUDIOS AND DESIGNERS

Similar to the logo design websites above, I find it very inspirational to view portfolios of designers and studios who produce quality work. Here are a few portfolios I came across recently:

Raja Sandhu

Raja Sandhu is a creative director living in Canada and has designed hundreds of logos. He has done work for clients such as Snoop Dogg and the State University of New York

Dache

Dache is a design studio founded by David Pache that is located in Switzerland. They have a large collection of recent logo designs that can help awaken ideas within you.

Common Brand

Common Brand is a major design studio that does branding, illustrations, flash animation website design & development, and even more. They have worked with major companies such as AOL and BMW Canada.

LOGO DESIGN BOOKS

book1.jpgbook2.jpgbook3.jpgbook4.jpg

FREE FONT SITES

Dafont

Dafont is probably the best known free font site around. They have them all neatly organized into a variety of categories. Fonts are available for both Mac and PC, and new fonts are added on a regular basis.

Urban Fonts

Urban Fonts is another truly great site that offers free fonts. It has made its way to the top in a short amount of time. They also have free dingbats, fonts for sale and forums where you can ask questions.

ASP 0104 : 80070057 Error at line 0

Response object error 'ASP 0104 : 80070057'

Operation not Allowed

/files.asp, line 0

Response オブジェクト エラー 'ASP 0104 : 80070057'

操作は許可されません

/files.asp, 行 0

上述的错误没有任何暗示错在什么地方。
There must be an endless loop etc that stops the code to run a line at all!
检查一下有没有死循环,比如 少了 RecordSet.MoveNext

Google SOAP Search API

I searched a lot of Google Web Service API articles and at last I found This one:
http://blogs.msdn.com/coding4fun/archive/2006/10/31/912079.aspx
And a comment read:
George said on April 20, 2007 2:35 PM:

Google stopped issuing these keys as of December 5 2006...http://code.google.com/apis/soapsearch/reference.html


In Google's Official site:
As of December 5, 2006, we are no longer issuing new API keys for the SOAP Search API. Developers with existing SOAP Search API keys will not be affected.
So don't bother yourself with apis. Download google's query result page directly and parser it.

And of course, DON'T ABUSE Google's services. Google Forbidden this!

2008年1月18日星期五

Two articles about Google Services.

Using the Google Search Web Service in ASP.NET (VB.NET)
http://www.bbits.co.uk/PlayGround/GoogleSearch/GoogleService.aspx

Integrating Google Search using the Google Web Services
http://www.c-sharpcorner.com/UploadFile/mchandramouli/IntegratingGoogleSearch11242005033911AM/IntegratingGoogleSearch.aspx

c#访问googleAPI

  • 准备工作

要使用googleAPI 来开发自己的桌面应用程序,先要做下面的准备工作:

1. 首先在下面地址http://www.google.com/apis/download.html下载the Google Web APIs Developer's Kit

2. 然后在下面地址https://www.google.com/accounts/NewAccount?continue=http://api.google.com/createkey&followup=http://api.google.com/createkey注册一个 license key 以使用google提供的搜索服务。

  • 新建一个Google Search应用程序

1. 新建一个Windows From 项目命名为Google Search

2. 添加Web引用,以便使用google web services。具体做法是将下载的the Google Web APIs Developer's Kit中的GoogleSearch.wsdl文件放入本地的服务器上,然后在VS中右键点击资源管理器中的引用,再选择添加Web引用,然后输入GoogleSearch.wsdl文件在本机服务器上的地址http://localhost/GoogleSearch.wsdl,更改Web引用名为GoogleSearch后,点击添加引用后返回。

3. 进行界面设计,添加3个控件,TextBox(用于输入关键字)Button(用于提交信息),RichTextBox(用于显示搜索结果信息)。如图:

4. 编写事件处理。

1) 添加命名空间。using Google_Search.googlesearch;

2) 双击Button控件,在Button的事件处理中添加下面的代码:

1 try
2
3 {
4
5 GoogleSearchService s = new GoogleSearchService();
6
7 GoogleSearchResult r = s.doGoogleSearch("NGYfW7dQFHKshnXPwvctLsaipk03YK2x", textBox1.Text, 0, 10, true, "", true, "", "", "");
8
9 ResultElement[] re = r.resultElements;
10
11 foreach (ResultElement n in re)
12
13 {
14
15 richTextBox1.AppendText(n.title+"\r");
16
17 richTextBox1.AppendText(n.snippet+"\r");
18
19 richTextBox1.AppendText(n.URL);
20
21 richTextBox1.AppendText("\n\r\r");
22
23 }

24
25 }

26
27
28
29 catch(Exception ee)
30
31 {
32
33 MessageBox.Show(ee.Message);
34
35 }

36
37

3) 按ctrl+F5就能测试应用程序了。

l GoogleSearchServicesdoGoogleSearch方法

需要进行搜索先建立一个GoogleSearchServices 类的对象,然后调用doGoogleSearch方法取得信息。下面是google提供的对该方法的描述。

public doGoogleSearch(string key, string q, int start, int maxResults, bool filter, string restrict, bool safeSearch, string lr, string ie, string oe)

下面对各个参数进行介绍:

Key:这是由google提供的一个认证用的ID,可以在http://www.google.com/apis/申请。由于目前是测试阶段,每个ID一天只提供1000次的搜索服务请求。

q:这个就是要搜索的关键字。string类型

start:结果开始的索引数,从0开始。 int 类型

maxresults:返回的结果数的最大值,最大为10int 类型

filter:用于标识是否对搜索的结果进行过滤,所进行的过滤是对于同一主机上的内容只返回1—2个结果。bool类型

restrict:用于限定搜索的国家或地区,如果为空,表示不限制。string 类型。

下表将列出所有能选的代号。

国家

代号

国家

代号

国家

代号

国家

代号

Andorra

countryAD

Estonia

countryEE

Kazakhstan

countryKZ

Qatar

countryQA

United Arab Emirates

countryAE

Egypt

countryEG

Lao People's Democratic Republic

countryLA

Reunion

countryRE

Afghanistan

countryAF

Western Sahara

countryEH

Lebanon

countryLB

Romania

countryRO

Antigua and Barbuda

countryAG

Eritrea

countryER

Saint Lucia

countryLC

Russian Federation

countryRU

Anguilla

countryAI

Spain

countryES

Liechtenstein

countryLI

Rwanda

countryRW

Albania

countryAL

Ethiopia

countryET

Sri Lanka

countryLK

Saudi Arabia

countrySA

Armenia

countryAM

European Union

countryEU

Liberia

countryLR

Solomon Islands

countrySB

Netherlands Antilles

countryAN

Finland

countryFI

Lesotho

countryLS

Seychelles

countrySC

Angola

countryAO

Fiji

countryFJ

Lithuania

countryLT

Sudan

countrySD

Antarctica

countryAQ

Falkland Islands (Malvinas)

countryFK

Luxembourg

countryLU

Sweden

countrySE

Argentina

countryAR

Micronesia, Federated States of

countryFM

Latvia

countryLV

Singapore

countrySG

American Samoa

countryAS

Faroe Islands

countryFO

Libyan Arab Jamahiriya

countryLY

St. Helena

countrySH

Austria

countryAT

France

countryFR

Morocco

countryMA

Slovenia

countrySI

Australia

countryAU

France, Metropolitan

countryFX

Monaco

countryMC

Svalbard and Jan Mayen Islands

countrySJ

Aruba

countryAW

Gabon

countryGA

Moldova

countryMD

Slovakia (Slovak Republic)

countrySK

Azerbaijan

countryAZ

United Kingdom

countryUK

Madagascar

countryMG

Sierra Leone

countrySL

Bosnia and Herzegowina

countryBA

Grenada

countryGD

Marshall Islands

countryMH

San Marino

countrySM

Barbados

countryBB

Georgia

countryGE

Macedonia, The Former Yugoslav Republic of

countryMK

Senegal

countrySN

Bangladesh

countryBD

French Quiana

countryGF

Mali

countryML

Somalia

countrySO

Belgium

countryBE

Ghana

countryGH

Myanmar

countryMM

Suriname

countrySR

Burkina Faso

countryBF

Gibraltar

countryGI

Mongolia

countryMN

Sao Tome and Principe

countryST

Bulgaria

countryBG

Greenland

countryGL

Macau

countryMO

El Salvador

countrySV

Bahrain

countryBH

Gambia

countryGM

Northern Mariana Islands

countryMP

Syria

countrySY

Burundi

countryBI

Guinea

countryGN

Martinique

countryMQ

Swaziland

countrySZ

Benin

countryBJ

Guadeloupe

countryGP

Mauritania

countryMR

Turks and Caicos Islands

countryTC

Bermuda

countryBM

Equatorial Guinea

countryGQ

Montserrat

countryMS

Chad

countryTD

Brunei Darussalam

countryBN

Greece

countryGR

Malta

countryMT

French Southern Territories

countryTF

Bolivia

countryBO

South Georgia and the South Sandwich Islands

countryGS

Mauritius

countryMU

Togo

countryTG

Brazil

countryBR

Guatemala

countryGT

Maldives

countryMV

Thailand

countryTH

Bahamas

countryBS

Guam

countryGU

Malawi

countryMW

Tajikistan

countryTJ

Bhutan

countryBT

Guinea-Bissau

countryGW

Mexico

countryMX

Tokelau

countryTK

Bouvet Island

countryBV

Guyana

countryGY

Malaysia

countryMY

Turkmenistan

countryTM

Botswana

countryBW

Hong Kong

countryHK

Mozambique

countryMZ

Tunisia

countryTN

Belarus

countryBY

Heard and Mc Donald Islands

countryHM

Namibia

countryNA

Tonga

countryTO

Belize

countryBZ

Honduras

countryHN

New Caledonia

countryNC

East Timor

countryTP

Canada

countryCA

Croatia (local name: Hrvatska)

countryHR

Niger

countryNE

Turkey

countryTR

Cocos (Keeling) Islands

countryCC

Haiti

countryHT

Norfolk Island

countryNF

Trinidad and Tobago

countryTT

Congo, The Democratic Republic of the

countryCD

Hungary

countryHU

Nigeria

countryNG

Tuvalu

countryTV

Central African Republic

countryCF

Indonesia

countryID

Nicaragua

countryNI

Taiwan

countryTW

Congo

countryCG

Ireland

countryIE

Netherlands

countryNL

Tanzania

countryTZ

Switzerland

countryCH

Israel

countryIL

Norway

countryNO

Ukraine

countryUA

Cote D'ivoire

countryCI

India

countryIN

Nepal

countryNP

Uganda

countryUG

Cook Islands

countryCK

British Indian Ocean Territory

countryIO

Nauru

countryNR

United States Minor Outlying Islands

countryUM

Chile

countryCL

Iraq

countryIQ

Niue

countryNU

United States

countryUS

Cameroon

countryCM

Iran (Islamic Republic of)

countryIR

New Zealand

countryNZ

Uruguay

countryUY

China

countryCN

Iceland

countryIS

Oman

countryOM

Uzbekistan

countryUZ

Colombia

countryCO

Italy

countryIT

Panama

countryPA

Holy See (Vatican City State)

countryVA

Costa Rica

countryCR

Jamaica

countryJM

Peru

countryPE

Saint Vincent and the Grenadines

countryVC

Cuba

countryCU

Jordan

countryJO

French Polynesia

countryPF

Venezuela

countryVE

Cape Verde

countryCV

Japan

countryJP

Papua New Guinea

countryPG

Virgin Islands (British)

countryVG

Christmas Island

countryCX

Kenya

countryKE

Philippines

countryPH

Virgin Islands (U.S.)

countryVI

Cyprus

countryCY

Kyrgyzstan

countryKG

Pakistan

countryPK

Vietnam

countryVN

Czech Republic

countryCZ

Cambodia

countryKH

Poland

countryPL

Vanuatu

countryVU

Germany

countryDE

Kiribati

countryKI

St. Pierre and Miquelon

countryPM

Wallis and Futuna Islands

countryWF

Djibouti

countryDJ

Comoros

countryKM

Pitcairn

countryPN

Samoa

countryWS

Denmark

countryDK

Saint Kitts and Nevis

countryKN

Puerto Rico

countryPR

Yemen

countryYE

Dominica

countryDM

Korea, Democratic People's Republic of

countryKP

Palestine

countryPS

Mayotte

countryYT

Dominican Republic

countryDO

Korea, Republic of

countryKR

Portugal

countryPT

Yugoslavia

countryYU

Algeria

countryDZ

Kuwait

countryKW

Palau

countryPW

South Africa

countryZA

Ecuador

countryEC

Cayman Islands

countryKY

Paraguay

countryPY

Zambia

countryZM

Zaire

countryZR

safeSearch:使用一个bool值表示是否过滤垃圾信息。

lr:对语言的限制,string类型可选代号如下表:

语言

代号

语言

代号

Arabic

lang_ar

Icelandic

lang_is

Chinese (S)

lang_zh-CN

Italian

lang_it

Chinese (T)

lang_zh-TW

Japanese

lang_ja

Czech

lang_cs

Korean

lang_ko

Danish

lang_da

Latvian

lang_lv

Dutch

lang_nl

Lithuanian

lang_lt

English

lang_en

Norwegian

lang_no

Estonian

lang_et

Portuguese

lang_pt

Finnish

lang_fi

Polish

lang_pl

French

lang_fr

Romanian

lang_ro

German

lang_de

Russian

lang_ru

Greek

lang_el

Spanish

lang_es

Hebrew

lang_iw

Swedish

lang_sv

Hungarian

lang_hu

Turkish

lang_tr

ie:输入所使用的字符编码。这个参数将被忽略,所有的输入都将采用UTF-8

oe:输出所使用的字符编码。这个参数将被忽略,所有的输出都将采用UTF-8

通过对这个方法的各个参数的设定可以是自己的应用程序在搜索方面更加人性化。具体使用时可以通过各种控件来收集这些信息。


l GoogleSearchResult

这个类用于存储搜索结果,下面介绍这个类的一些重要属性:

1. estimatedTotalResultsCount 所有与关键字有关的信息的总数

2. searchTime 提交信息到返回信息所用的时间。

3. searchTips 根据关键字提供一些与关键字相关的关键字,供选择。

4. resultElements 返回一个数组,用于存储返回结果的每一项。

l Result Element

这个类的是搜索的结果中的每一项,所有的结果处理都依靠这个类。下面是这个类的一些属性的介绍:

1. URL 显示结果网页的url

2. snippet 返回在目标网页中摘录一些包含关键字片段。

3. title 目标网页的标题。

4. hostname 该参数显示目标网页所在的主机明。

5. summary 如果目标网页在ODP 目录中存在,则返回摘要信息。

6. directoryTitle 显示ODP 目录的标题。

通过这两个类可以取得各种与查询有关的信息,通过以上的介绍,基本可以使用googleAPI提供的全部功能。