huyutian

他强由他强,清风拂山岗;他横由他横,明月照大江。他自狠来他自恶,我自一口真气足

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  20 随笔 :: 47 文章 :: 22 评论 :: 0 Trackbacks

#

Google Protocol Buffer是一种用来描述网络协议很高效的开发工具。这篇文章写得通俗易懂,简单明了。很适合初次接触的人。以后找机会在项目中尝试一下这种工具,在这里先做个标记。
http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html?ca=drs-
posted @ 2011-07-19 09:55 胡雨田 阅读(690) | 评论 (0)编辑 收藏

在写一个包含多个Project的程序时,采取分布编译生成OBJ文件,然后主程序组装,结果调试信息丢失。
warning LNK4099: PDB 'vc90.pdb' was not found with 'E:\Projects\XXXXX\Lib\log4cplusSD.lib' or at 'E:\Projects\XXXXX\Debug\vc90.pdb';
为解决这个问题搜索了下MSDN中关于PDB文件生成的一些解释汇集在这里。
1)http://msdn.microsoft.com/zh-cn/library/yd4f8bd1(v=vs.80).aspx
程序数据库 (PDB) 文件保存着调试和项目状态信息,使用这些信息可以对程序的调试配置进行增量链接。当以 /ZI 或 /Zi(用于 C/C++)生成时,将创建一个 PDB 文件。

在 Visual C++ 中,/Fd 选项用于命名由编译器创建的 PDB 文件。当使用向导在 Visual Studio 中创建项目时,/Fd 选项被设置为创建一个名为 project.PDB 的 PDB。

如果使用生成文件创建 C/C++ 应用程序,并指定 /ZI/Zi 而不指定 /Fd 时,则最终将生成两个 PDB 文件:

  • VC80.PDB   (更笼统地说就是 VCx0.PDB,其中 x 表示 Visual C++ 的版本。)该文件存储各个 OBJ 文件的所有调试信息并与项目生成文件驻留在同一个目录中。

  • project.PDB   该文件存储 .exe 文件的所有调试信息。对于 C/C++,它驻留在 \debug 子目录中。

每当创建 OBJ 文件时,C/C++ 编译器都将调试信息合并到 VCx0.PDB 中。插入的信息包括类型信息,但不包括函数定义等符号信息。因此,即使每个源文件都包含公共头文件(如 <windows.h>),这些头文件中的 typedef 也只存储一次,而不是在每个 OBJ 文件中都存在。

链接器将创建 project.PDB,它包含项目的 EXE 文件的调试信息。project.PDB 文件包含完整的调试信息(包括函数原型),而不仅仅是在 VCx0.PDB 中找到的类型信息。这两个 PDB 文件都允许增量更新。链接器还在其创建的 .exe 或 .dll 文件中嵌入 .pdb 文件的路径。

Visual Studio 调试器使用 EXE 或 DLL 文件中的 PDB 路径查找 project.PDB 文件。如果调试器在该位置无法找到 PDB 文件或者如果路径无效(例如,如果项目被移动到了另一台计算机上),调试器将搜索包含 EXE 的路径,即在“选项”对话框(“调试”文件夹,“符号”节点)中指定的符号路径。调试器不会加载与所调试的二进制不匹配的 PDB。

2)http://msdn.microsoft.com/zh-cn/library/958x11bc(v=vs.80).aspx

下表描述了这些选项。

不产生任何调试信息,因此编译较快。

/Z7

生成包含用于调试器的完整符号调试信息的 .obj 文件。符号调试信息包括变量的名称和类型以及函数和行号。不会生成任何 .pdb 文件。

对于第三方库的发布者,不生成 .pdb 文件是一个优点。但是,在链接和调试期间,用于预编译头的 .obj 文件是必需的。如果 .pch 对象文件中只有类型信息(没有代码),则还必须使用 /Yl(为调试库插入 PCH 引用) 进行编译。

/Zi

产生包含用于调试器的类型信息和符号调试信息的程序数据库 (PDB)。符号调试信息包括变量的名称和类型以及函数和行号。

/Zi 不影响优化。但是,/Zi 的确暗示了 /debug;有关更多信息,请参见 /DEBUG(生成调试信息)

类型信息放置在 .pdb 文件而不是 .obj 文件中。

可以将 /Gm(启用最小重新生成)/Zi 结合使用,但使用 /Z7 编译时不能使用 /Gm

使用 /Zi/clr 编译时,DebuggableAttribute 属性将不会被放入程序集元数据中;如果要使用该属性,则必须在源代码中指定它。该属性可影响应用程序的运行时性能。有关 Debuggable 属性如何影响性能以及如何减轻性能影响的更多信息,请参见令映像更易于调试

/ZI

以支持“编辑并继续”功能的格式产生如上所述的程序数据库。如果想使用“编辑并继续”调试,则必须使用此选项。因为大多数优化与“编辑并继续”不兼容,所以使用 /ZI 会禁用代码中的所有 #pragma optimize 语句。

/ZI 会导致在编译中使用 /Gy(启用函数级链接)

/ZI/clr(公共语言运行库编译) 不兼容。

Note注意

/ZI 只可用于面向 x86 的编译器中;此编译器选项不可用于面向 x64 或 Itanium 处理器系列 (IPF) 的编译器中。

编译器将程序数据库命名为 project.pdb。如果编译没有项目的文件,则编译器将创建名为 VCx0.pdb. 的数据库,其中 x 是正在使用的 Visual C++ 的主版本。编译器将 PDB 的名称嵌入每个使用此选项创建的 .obj 文件中,从而使调试器了解符号和行号信息的位置。当使用此选项时,.obj 文件将较小,因为调试信息存储在 .pdb 文件中而不是 .obj 文件中。

如果从使用此选项编译的对象创建库,则在将库链接到程序时,关联 .pdb 文件必须可用。因此,如果发布此库,就必须发布 PDB。

若要不使用 .pdb 文件创建包含调试信息的库,必须选择编译器的 C 7.0 兼容 (/Z7) 选项。如果使用预编译头选项,则预编译头和其他源代码的调试信息都放在 PDB 中。指定了“程序数据库”选项时将忽略 /Yd 选项。

3)http://msdn.microsoft.com/zh-cn/library/dd998269.aspx

/PDBALTPATH(使用备用 PDB 路径)

Visual Studio 2010
/PDBALTPATH:pdb_file_name

其中:

pdb_file_name

.pdb 文件的路径和文件名。

使用此选项可以在已编译二进制文件中为程序数据库 (.pdb) 文件提供一个备用位置。 通常,链接器将 .pdb 文件的位置记录到它所生成的二进制文件中。 使用此选项可以为程序数据库文件提供另一个路径和文件名。 /PDBALTPATH 提供的信息不会更改实际 .pdb 文件的位置或名称;它更改链接器写入二进制文件中的信息。 这样,您可以提供一个独立于生成计算机文件结构的路径。 此选项的两个常见用途是提供网络路径或不包含路径信息的文件。

pdb_file_name 的值可以是任意字符串,也可以是环境变量(即 %_PDB%)。 链接器将环境变量(如 %SystemRootr%)扩展为它的值。 链接器定义环境变量 %_PDB% 和 %_EXT%。 %_PDB% 扩展为实际 .pdb 文件的文件名(不包含任何路径信息),%_EXT% 是所生成的可执行文件的扩展名。

 

posted @ 2011-07-05 22:10 胡雨田 阅读(2573) | 评论 (0)编辑 收藏

很简单的一款儿童学习数学的软件,长期使用时需要注册码,下面简单分析一下注册算法。
注册码必须是25位,形如AAAAa-BBBBb-CCCCc-DDDDd-EEEEe.真正有用的只是AAAABBBBCCCCDDDD16位,其他位置可以随便填写。
004015B1                 call    ds:_mbscmp处是比较注册码是否正确。
正确的注册码需要用硬盘的id号计算,比如我的虚拟机8位硬盘id:18e9de99
1)先进行变形在2,4,6,8,10,12,14,16位分别插入1,2,3,4,5,6,7,8.多次变形后生成24位长字符串11128324e5369748d5e69798。
2)按照6个字符一段分成4组,按照3)4)5)计算生成4个4位共16位字符串
3)每一组的后三字符逐位与种子数组【0a,13,09,0c,0b,0a,08】相乘后求和,并转换为字符串。
4)计算3)中生成字符串的第3位与第4位差的绝对值,存入m。
5)对3)生成的字符串进行变形,先把第1位加上m;然后前4位每位各加上0x11,生成4位字符串
按照1)-5)步骤重复两次,第一次生成JBCJHBHCEGHJHCJE,第二次生成ICDJCDCCCHBBCIFF。
ICDJCDCCCHBBCIFF就是对应上面的AAAABBBBCCCCDDDD16位注册码了。

所以我的虚拟机的注册码就是ICDJ1-CDCC2-CHBB3-CIFF4-00000。注册成功后你的注册码保存在dat\diary.dat文件中。
posted @ 2011-06-26 11:18 胡雨田 阅读(559) | 评论 (0)编辑 收藏

对于socket编程一直有一种误解:socket的阻塞连接下应该调用send/recv来发送和接收数据,而无阻塞连接下应该用WSASend/WSARecv函数来发送和接收数据。其实socket工作模式与调用哪个收发函数没有任何关系,自己写段简单的代码测试下就知道了。无阻塞模式下,send/recv都是立即返回的。并不会等待发送或接收完成才返回。测试还发现选择模式下无阻塞连接,调用connect函数会立即返回,随后调用select,在连接建立时会设置fdWrite。
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
    
return -1;
}


// Set the connection to non-blocking mode
unsigned long ulMode = 1;
if (::ioctlsocket(s, FIONBIO, &ulMode) != 0)
{
    s 
= INVALID_SOCKET;
    
return -1;
}


char szHost[128= "www.myhost.com";
int nPort = 8000;
char szBuffer[1024= "test socket function.\n"

addrinfo aiHints;
addrinfo 
*aiList = NULL;
memset(
&aiHints, 0sizeof(aiHints));
aiHints.ai_family 
= AF_INET;
aiHints.ai_socktype    
= SOCK_STREAM;
aiHints.ai_protocol    
= IPPROTO_TCP;
if (0 != ::getaddrinfo(szHost, NULL, &aiHints, &aiList))
{
    
//m_nLastError = WSAGetLastError();
    ::WSASetLastError(WSAEINVAL);
    
return -1;
}


fd_set fdRead, fdWrite;
FD_ZERO(
&fdRead);
FD_ZERO(
&fdWrite);
FD_SET(s, 
&fdRead);
FD_SET(s, 
&fdWrite);
struct timeval tv;
tv.tv_sec 
= 3;
tv.tv_usec 
= 0;

SOCKADDR_IN hostAddr;
hostAddr 
= *((SOCKADDR_IN*)aiList->ai_addr);
hostAddr.sin_port 
= ::htons(nPort);
int retCode = ::connect(s, (SOCKADDR*&hostAddr, sizeof(hostAddr));
if (retCode == SOCKET_ERROR)
{
    
int errCode = WSAGetLastError();
    
if (errCode != WSAEWOULDBLOCK)
    
{
        ::closesocket(s);
        s 
= INVALID_SOCKET;
        
return -1;
    }

}

retCode 
= ::select(0&fdRead, &fdWrite, NULL, &tv);
if (retCode > 0)
{
    
if (FD_ISSET(s, &fdRead))
    
{
        printf(
"error!\n");
    }

    
if (FD_ISSET(s, &fdWrite))
    
{
        
//connection has succeeded.
        printf("connect success!\n");
        FD_SET(s, 
&fdWrite);
        FD_ZERO(
&fdRead);
        retCode 
= ::select(0&fdRead, &fdWrite, NULL, &tv);
        
if (retCode > 0)
        
{
            
if (FD_ISSET(s, &fdRead))
            
{
                printf(
"error!\n");
            }

            
if (FD_ISSET(s, &fdWrite))
            
{
                retCode 
= send(s, szBuffer, strlen(szBuffer), 0);
                
if (retCode > 0)
                
{
                    retCode 
= recv(s, buf, 10230);
                    
if (retCode == SOCKET_ERROR)
                    
{
                        retCode 
= WSAGetLastError();
                    }

                    
else if (retCode > 0)
                    
{
                        printf(
"recv %d bytes.\n", retCode);
                    }

                }

            }

        }

    }

}

return 0;
很多问题要想深入理解最好的方法就是写一段短的测试程序验证一下,既不要想当然也不要道听途说。
posted @ 2011-06-19 22:47 胡雨田 阅读(503) | 评论 (0)编辑 收藏

http://anaturb.net/C/ccc.htm
posted @ 2010-11-22 22:31 胡雨田 阅读(448) | 评论 (0)编辑 收藏

stanza是ipod/iphone上的免费读书软件,功能非常实用。最近由于我的ipod系统出现问题,想导出stanza下载的电子书后重装系统,结果折腾了好久。

在stanza官网上搜索了下,发现很多人都有和我一样的需求,作者也适时推出了Stanza Book Restore Tool,我立马下载回来。这个工具是从ipod备份(通过itune备份)中导出stanza电子书。但是我一运行这个工具就提示我RE:java.lang.IllegalArgumentException: Cannot find backup folder错误。
会不会是这个工具不支持中文目录呢?我把itunes备份目录copy到c:根目录下。结果还是一样的错误提示,这下没辙了。重新回到stanza官网搜索,发现了这篇文章http://www.lexcycle.com/node/1864。摘录如下

RE:java.lang.IllegalArgumentException: Cannot find backup folder

This "can't find" problem is due to the checks for "backupFolder.length() == 0" in StanzaBookRestore.run(). That File.length() call will always return 0 for a folder/directory under Java 1.6.0 (on my Windows XP machine, anyway).

So, no matter what backup folder I pick, the code always thinks it is invalid and "over smartifies" and calls getDefaultBackupFolder(), which makes backupFolder = "Backup" ... which is NOT what I asked for. (I prefer software to just tell me when I input an invalid value instead of trying to do invisible "smart" things for me. Makes finding bugs like this easier.)

Anyway, I just removed all checks for backupFolder.length() == 0 from StanzaBookRestore.run(), and it seems to work fine.

这个解决办法是要修改stanzabookrestore.jar中的StanzaBookRestore.java文件,将StanzaBookRestore.run()函数中的所有backupFolder.length() == 0条件检查去掉。据说是Windows下才有这个问题。
以前我可没有编译过java。只好下载了java jdk以及XJad反编译工具。先用XJad反编译stanzabookrestore.jar,然后安装jdk,修改StanzaBookRestore.java并重新编译为jar。要说明的一点是,stanzabookrestore.jar中已经带有所有java源文件了。XJad反编译后的java文件编译时有点小问题,我是直接从作者的源文件替换、修改后重新编译的。
说说java的编译过程。
1.执行javac ????.java生成 ????.class
2.建一个manifest.mf 文件用来申明main函数所在类,这里可以直接用作者原来的manifest.mf
3.用jar 打包class文件。
先将所有class文件copy到classes文件夹,然后在上一级目录下建一个myjar.bat文件,内容如下:
set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_21
set PATH=%JAVA_HOME%\bin
set CLASSPATH=%JAVA_HOME%\lib\tools.jar;
jar cvfm stanzabookrestore.jar MANIFEST.MF -C classes/ .
运行myjar.bat就重新生成了stanzabookrestore.jar.
没想到搞个stanza电子书的备份居然要学习java的编译。不过也许以后还用得着,先记在这里吧。
重新编译后的在这里http://www.cppblog.com/Files/huyutian/stanzabookrestore.zip
posted @ 2010-08-01 10:18 胡雨田 阅读(2202) | 评论 (0)编辑 收藏

最近将编程环境升级到VS2008,结果很多原来正常编译的projects都出现了编译告警和错误。花了一周多时间熟悉下VS2008.,总体来看vs2008在64位编程、多核/多处理器编译、函数的安全性、c++模板的支持方面都有很多改进。但是在升迁到新的环境之前也有很多问题需要重新考虑了。
1。time_t在vs2003中默认是32位__time32_t,现在默认为__time_64_t了,如果要继续兼任原有代码必须在头文件的开始处增加如下语句
#ifndef _USE_32BIT_TIME_T
#define _USE_32BIT_TIME_T//use __time32_t
#endif
2.sprintf,memcpy之类的函数都会提示告警,要继续使用这些函数必须在定义宏
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
3.编译时出现:无法打开vc90.pdb的错误。在MSDN上搜索了一下,解决办法是http://msdn.microsoft.com/en-us/library/hk8k8k4h(VS.80).aspx
原文贴在这里,主要是因为vs2008支持一在个solutions下多个不相互依赖的project的并行编译,当然前提是你的cpu是多核的或者有多个cpu。如果多个projects的output目录相同就会碰到同时写入vc90.pdb的问题。知道了原因就很好解决了。
Title: You may receive a "PRJ0008" or "C2471" or "C1083" or "D8022" or "LNK1103" or similar error message when you try to build a solution in Visual C++

Symptoms:

  • D8022 : Cannot open 'RSP00000215921192.rsp'
  • PRJ0008 : Could not delete file 'vc90.idb'.
  • C1083 : Cannot open program database file 'vc90.pdb'
  • C2471 : Cannot update program database 'vc90.pdb'
  • LNK1103 : debugging information corrupt.
Cause:

This problem occurs when all of the following conditions are true:

  1. You have a solution with more than one project in it.
  2. Two or more of the projects are not dependent on each other.
  3. You have parallel builds enabled. (Tools -> Options: Projects and Solutions, Build and Run: "maximum number of parallel project builds" is set to a value greater than 1)
  4. You are building on a system with multiple CPUs (cores).
  5. Two or more of the non-dependent projects are configured to use the same Intermediate and/or Output directory.
  6. A specific race condition in mspdbsrv.exe remains uncorrected.
Resolution:

To resolve the problem do one or more of the following:

  • Reconfigure the non-dependent projects to specify an Intermediate and Output directory that is different from one another, e.g. Output Directory = "$(SolutionDir)$(ProjectName)\$(ConfigurationName)", Intermediate Directory = "$(OutDir)".
  • Adjust your solution's project dependencies (Project -> Project Dependencies...) so that each is dependent on another.
  • Disable parallel builds.
  • Add the "/onecpu" boot option to your boot.ini file.
  • Change you BIOS settings to enable/use only one CPU.
  • File a problem report with Microsoft Technical Support and keep bugging the *** out of them until they eventually fix mspdbsrv.
posted @ 2010-07-25 17:48 胡雨田 阅读(1832) | 评论 (0)编辑 收藏

今年4月zlib发布了1.2.5版,修正了几个bug,增加了新功能(目前我还用不上).
最近准备在自己的程序中用这个版本。结果怎么也编译通不过。折腾了我一整天才搞定,发现是两个小的设置没有弄好。哎。。。
新的1.2.5版本只提供了vc9、vc10两个project配置文件.我用项目版本转换文件怎么也不能转到vc7.1下。没办法只好装了一个vc2008重新编译。
把zlib 1.2.5加入自己的项目,编译时有两点要注意
1.就是zlib 1.2.5源代码包中\contrib\vstudio\readme.txt中说的在使用zlib要预定义宏ZLIB_WINAPI,否则无法编译通过。
- To use zlibwapi.dll in your application, you must define the  macro ZLIB_WINAPI when compiling your application's source files.
2.链接时,除了#pragma comment(lib, "zlibvc.lib")添加引入库外,还要注意Character Set的设置要统一。否则也会出现链接错误,提示找不到_compress外部变量。

后记(2011-6-19)
我的编程环境已升级VS2008,又想在项目中使用ASM版本的ZLIB,重新从zlib.net下载后,直接使用zlib-1.2.5\contrib\vstudio\vc9下的zlibvc项目文件编译出错。发现是zlib-1.2.5\contrib\masmx86下的OBJ文件没有生成。进入VS2008命令行环境,运行bld_ml32.bat生成两个obj文件。重新在集成环境下编译就没问题了。但是如果是使用ZLIB的静态库版本,一定注意要将这两个obj文件包含到最终的zlibvc.lib中去。否则在自己的应用项目中编译时会提示如下错误。1>zlibr.lib(inflate.obj) : error LNK2001: unresolved external symbol _inflate_fast
1>zlibr.lib(deflate.obj) : error LNK2001: unresolved external symbol _longest_match
1>zlibr.lib(deflate.obj) : error LNK2001: unresolved external symbol _match_init
把两个obj文件包含到zlibvc.lib的方法是,Project->Property->Librarian->Additional Dependencies 加入inffas32.obj match686.obj,同时Additional Library Directories设置正确。
另外,如果使用命令行编译进入zlib-1.2.5\win32目录运行下面的命令就可以了。
nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="inffas32.obj match686.obj"               (use ASM code, x86)
nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF"  OBJA="inffasx64.obj gvmat64.obj inffas8664.c"  (use ASM code, x64)
posted @ 2010-07-24 17:41 胡雨田 阅读(6681) | 评论 (4)编辑 收藏

M$的编译器,低版本的总是无法打开高版本的project项目文件,让人非常郁闷。其实有些小型项目用VC6.0或者vc2003就足够了。没必要装那么大腹便便的vs2008,或者最新的vs2010.这时候一个不同版本间的项目转换工具就非常必要了。常用工具收藏于此,查阅方便。
Visual Studio Project Converter
http://sourceforge.net/projects/vspc/
VSPC is the console utility for converting between project formats for various versions of Microsoft Visual Studio. Currently the project supports VS 2002, 2003, 2005 and 2008. Original version of the code was created by Stoyan Damov
命令行工具,支持VS2002,2003,2005以及2008不同版本之间的互相转换,非常方便。似乎不支持vc6.0与以上版本互相转换。

vc7.0转换VC6.0项目的工具要看这里
http://www.arstdesign.com/articles/prjconverter.html
或者从codeproject下载
http://www.codeproject.com/KB/applications/prjconverter.aspx

值得一提的是,以上两个工具都是开源的,有兴趣的可以研究下不同版本间格式的变化。
posted @ 2010-07-03 22:38 胡雨田 阅读(2764) | 评论 (1)编辑 收藏

最近一直在学习STL 标准容器的用法,感觉相关资料太少,上手不易。大多数学习资料使用的例子是关于int或者char*等简单数据的,对于自定义结构、类的标准容器讲述很少。今天搜索到baidu上的晕晕倒倒网,感觉关于标准容器的用法总结的非常好,实例详尽,一看就明白。欣喜之下,不告而取,以防遗忘。如果原作者有意见,不让转贴,请邮件告知,必当立即清除。
posted @ 2010-02-08 00:09 胡雨田 阅读(467) | 评论 (0)编辑 收藏

仅列出标题
共2页: 1 2