分享

mingw/vc2008移植问题记录

 云将东游 2018-05-17
关于VC和gcc的区别,请参考以下链接:

gccとVC(日文)

http://homepage1./herumi/prog/gcc-and-vc.html

 

(20131119)

超初心者のプログラム入門

http://www.eonet./~maeda/index.html

 

 

Problem 1: VC2008 运行时库
属性页->C/C++->代码生成->运行时库(一般是MTd和MT)

 

Problem 2: inline函数重定义问题,可以考虑用#if屏蔽掉
#if defined(_MSC_VER) && (_MSC_VER < 1500) //VC 9
inline int inet_pton(int af, register const char *cp, struct in_addr *addr)

 

Problem 3: libevent.lib 依赖问题。
如果使用VC2008,并且建立起libevent源代码工程。可以考虑使用“链接器->输入->附加依赖项”,这样就不再需要添加libevent.lib

 

Problem 4: errno赋值问题
errno = 0需要改为set_errno(0);
原因是vc2008的编译器在多线程时不允许你直接给errno赋值,貌似是为了线程安全,这时候就得写个宏。

 

 

C代码  收藏代码
  1. #if defined(_MT) || defined(_DLL)  
  2. # define set_errno(x)    (*_errno()) = (x)  
  3. #else  
  4. # define set_errno(x)    errno = (x)  
  5. #endif  

 

 

不知道linux怎么处理线程安全(好像linux根本就不需要这么复杂)。

 

Problem 5:APR导入问题。
如果有一天突然想用APR或APU来编程,你就得遇到这种囧问题——不知道怎么在vc2008里链接。
一种方法是:
宏定义添加
APR_DECLARE_EXPORT(补充:或者APU_DECLARE_EXPORT)
WIN32
确保是动态导出api和动态导入APR DLL

附加依赖项目选择使用动态链接的lib(以防万一把apr和apu的都加上)
libapr-1.lib libaprutil-1.lib
如果不知道apr为何物,就最好别管这种复杂问题(Apache httpd的代码和API需要高手才看得懂的)
推荐用动态库(不会遇到一堆链接错误)如果用静态库要改用另一套lib和APR_DECLARE_STATIC

 

Problem 6: 函数声明和定义不同。
可能vc2008会对类型很敏感。最好改为统一。

 

Problem 7: snprintf问题
Windows SDK没有snprintf这个函数,用_snprintf代替

 

 

C代码  收藏代码
  1. #ifndef snprintf  
  2. #define snprintf _snprintf  
  3. #endif  

 

 

Problem 8: strtoll和strtoull问题

 

 

C代码  收藏代码
  1. #if _MSC_VER < 1300  
  2. #define strtoll(p, e, b) ((*(e) = (char*)(p) + (((b) == 10) ? strspn((p), "0123456789") : 0)), _atoi64(p))  
  3. #else  
  4. #define strtoll(p, e, b) _strtoi64(p, e, b)   
  5. #endif  
  6.   
  7. #ifndef strtoull  
  8. #define strtoull strtoul  
  9. #endif  

 

 

遇到这种问题需要查SDK的手册,你会发现有个叫_atoi64的API(这个函数很早就有了,用于32位操作系统上,定义在stdlib.h)。
当然如果你不喜欢上面代码写得那么复杂,可以一概改为_atoi64。另外,还需要知道有个关键字__int64,
可以用它表示有符号和无符号的64位整数(很少出现,除非你要用64位来提高性能)
_strtoi64的用法稍微不同。还有个叫_i64toa的API,是_atoi64的逆转换。

 

补充:可能对于64位整数,还要考虑格式化字符串printf的问题,所以问题远没有这么简单。

 

Problem 9:符号无定义。
比如你用了TransmitFile,你就得加mswsock.lib(不过好像加的顺序有讲究的)
如果不知道加什么,就查sdk帮助和搜索,一般微软会很热心地注明这个API需要用那个lib去
链接。把所有lib加上去试也可以(只是这种方法有点菜)

 

Problem 10:MySQL UDF问题
比较通用的方法是写个.def文件
LIBRARY "xxx"
EXPORTS
...
然后在工程中加入这个def
编译好dll后拷贝到
C:\Program Files (x86)\MySQL\MySQL Server 5.1\lib\plugin
或者根据show variables like "plugin_dir";判断插件位置
如果涉及别的dll,需要把依赖dll拷贝到PATH的路径下,例如
C:\Program Files (x86)\MySQL\MySQL Server 5.1\bin
否则mysqld会因为缺乏dll而启动不了UDF而认为UDF不存在。
创建SQL类似于CREATE FUNCTION xxx RETURNS INT SONAME "xxx.dll";
安装成功后select name, dl from mysql.func;查看
要调试UDF可以用fprintf(stderr,...)的方法,然后用mysqld --console来启动mysqld。
另外最好用debug版测试,万一崩溃了,mysqld会把输出一些堆栈信息到控制台上。

 

Problem 11: WSAStartup和memset问题

 

 

C代码  收藏代码
  1. #ifdef WIN32  
  2.  {  
  3.   WSADATA wsaData;  
  4.   if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0) {  
  5.    fprintf(stderr, "Socket Initialization Error. Program  aborted\n");  
  6.    return 0;  
  7.   }  
  8.  }  
  9. #endif  

 

 

这是windows的特有问题(写linux网络程序的人大概会很郁闷),
如果有一天发现getaddrinfo返回非零,
检查一下main函数有没有加WSAStartup。(连127.0.0.1都解析不了会很可笑)。
另外memset也是个需要注意的问题,例如初始化struct addrinfo变量hints需要
memset(&hints, 0, sizeof (hints));(有时候你忽略这个问题会出现一些古怪的结果)
然后给某个成员变量赋值。
linux的写法就不会那么复杂,它用C99的写法,在初始化时直接给变量的成员函数赋初始值。
顺便一提VC支持字符串的全0初始,例如char s[10] = {0};比单纯写char s[10];要安全得多。

 

更正:

VC其实可以像gcc那样给结构体对象赋初值,只不过不是写成 type a={.x = 10, };

而是写成type a={a.x = 10,};所以没必要用memset(低版本的VC则有必要?)

 

problem 12:缺少BSD套接字头文件

在linux网络编程中经常会出现

#include <netinet/tcp.h>
#include <arpa/inet.h>

有时还会有

#include <sys/socket.h>

还有其他,如果只是使用BSD套接字,

问题是,mingw没有(VC也是)。

但windows上的确存在BSD套接字API的子集,只不过需要包含的头文件不是上面那些,而是

 

 

C代码  收藏代码
  1. #include <winsock2.h>  
  2. #include <ws2tcpip.h>  

 

 

如果对这个问题感兴趣,可以参考这些资料:

 

* memcached1.2.6-win32移植的源代码

http://code./memcached/

 

*PostgreSQL的源码(\src\include\port\win32),对win32的移植

http://www./ftp/source/ 

 

(注:VC6似乎不行,待考)

 

problem 13:缺少sys/poll.h

win32没有现成的机制实现poll(轮询),也就是说:poll()不可移植

http://lists./mingw-users/msg05987.html

不过事实上有人给出poll()的非正式实现:

 (未经试验,不过好像可以试试看)

* libmemcached

/poll/poll.c

https:///libmemcached/+download

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

(2010-09-10:补充drizzle,发现它的源代码包中带有poll.c,不知道是否可用)

* drizzle

https:///drizzle

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

如果你使用cygwin,这个问题可以忽略(因为默认是有poll.h和poll()的实现)

(补充:

poll其实可以在msys的SDK中使用

msysDVLPR-1.0.0-alpha-1.tar.gz

但最终生成的exe导入了MSYS-1.0.DLL,而MSYS-1.0.DLL不可以单独使用(依赖于msys)

如果只用于msys控制台,可以尝试用这个SDK(gcc version 2.95.3-1)

安装教程:

http://www./wiki/HOWTO_Create_an_MSYS_Build_Environment

注意,它需要与msys目录合并,不是放在/mingw目录下

继续补充:

poll其实有win32的port,参考

WSAPoll

http://msdn.microsoft.com/en-us/library/ms741669(VS.85).aspx

不过这个API仅用于Vista以上

 

problem 14: pthread-w32静态库造成程序崩溃的问题。

由于dll.c中dllmain()调用了这两个API(定义在pthread.h)

PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void);
PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void);

如果pthread-w32被静态链接到程序中,需要在main()函数开头调用pthread_win32_process_attach_np初始化,否则程序会崩溃,且很难找到崩溃的原因(即使使用CDT调试)。

(2014/01/23补注:)代码如下:(在main函数最开始的地方执行)

C代码  收藏代码
  1. #ifdef __MINGW32__  
  2.     ptw32_processInitialize();  
  3.     //ptw32_processTerminate();  
  4. #endif  

 

 

 

problem 15: 关于VC6构造函数的初始化表的问题。

不可以使用带命名空间的基类。

例如class X:public std::Y{}

构造函数X():std::Y(0),...{}是编译出错的,

需要绕圈,用typedef std::Y std_Y,然后再初始化:X():std_Y(0),...{}

 

problem 16:关于VC6的模板参数和嵌套问题。

有些时候,如果没有用到模板参数,那么template可以省略,

但对于VC6来说,省略template<class T>有时就偏偏不行。

VC6似乎不能把嵌套template成员函数单独写再类定义外部。

例如template<class T> template<class C>...

一种解决办法是,放在类定义内部。

 

problem 17:VC6在成员函数中调用基类方法可能会编译失败。

原因不明,不过用某些方法绕过这种编译错误,例如使用未被覆盖或重载的方法代替(废话。。。)

 

problem 18: 使用winsock的API,在VC2008编译时出现大量的错误:

1>c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(91) : warning C4005: “AF_IPX”: 宏重定义
1>        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(460) : 参见“AF_IPX”的前一个定义

一般是因为出现这样的包含

#include <windows.h>
#include <winsock2.h>

导致一堆宏重定义

使用宏WIN32_LEAN_AND_MEAN可以屏蔽之(应该。。。)

用#define或者VC2008工程的预处理器设置均可。

 

problem 19: 线程局部变量的区别:

 

 

mingw32 does not support __thread (thread local storage).
but msvc support like it with _declspec(thread).
however mingw32 can ignore that.

 

参见:https://github.com/mattn/mod_perlite/commit/4f811433266d90d33568a5680c1499946a3bd897

20160926

可以参考这篇,引用自tbox/tboox:

线程局部存储tls的使用

http:///cn/2016/09/28/thread-local/

写道
gcc和clang的__thread修饰符
windows下msvc的__declspec(thread)修饰符
pthread库pthread_setspecific和pthread_getspecific接口
windows下的TlsSetValue和TlsGetValue

 

 

problem 20:asprintf和vasprintf

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

注意,这里有个开源实现(未试验)

http://www./software/snprintf/

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

出现在lua-checker的代码中

http://code.google.com/p/lua-checker/

这两个函数VC没有,需要用特殊方法近似地模拟,一种方法是使用vsnprintf(低版本的VC可能没有这个函数)(20150808:VC6有个函数叫_vsnprintf,但没有_vscprintf,也没有对应的_s版本)

 

C代码  收藏代码
  1. #ifdef _MSC_VER  
  2. #pragma warning(disable:4065)  
  3. #pragma warning(disable:4996)  
  4.   
  5. /* 
  6. 用malloc分配内存,在程序结束后自动回收 
  7. see  
  8. http://pdfrecompressor./svn-history/r40/trunk/jbig2enc_modified/jbig2.cc 
  9. */  
  10. // -----------------------------------------------------------------------------  
  11. // Windows, sadly, lacks asprintf  
  12. // -----------------------------------------------------------------------------  
  13. #include <stdarg.h>  
  14. static int asprintf(char **strp, const char *fmt, ...)   
  15. {  
  16.     va_list va;  
  17.     va_start(va, fmt);  
  18.     const int required = vsnprintf(NULL, 0, fmt, va);  
  19.     char *const buffer = (char *) malloc(required + 1);  
  20.     const int ret = vsnprintf(buffer, required + 1, fmt, va);  
  21.     *strp = buffer;  
  22.     va_end(va);  
  23.     return ret;  
  24. }  
  25.   
  26. static int vasprintf(char **strp, const char *fmt, va_list va)  
  27. {  
  28.     const int required = vsnprintf(NULL, 0, fmt, va);  
  29.     char *const buffer = (char *) malloc(required + 1);  
  30.     const int ret = vsnprintf(buffer, required + 1, fmt, va);  
  31.     *strp = buffer;  
  32.     return ret;  
  33. }  
  34.   
  35. #endif  

 

另一种做法是使用临时文件:

totem-plparser

https://github.com/zsx/totem-plparser

https://github.com/zsx/totem-plparser/blob/OAH/lib/asprintf.c

实现大概是这样:

 

C代码  收藏代码
  1. #include "config.h"  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <stdarg.h>  
  5.   
  6. #ifdef _WIN32  
  7. #include <windows.h>  
  8. #endif  
  9.   
  10. int totem_private_asprintf(char **out, const char *fmt, ...)  
  11. {  
  12.     va_list ap;  
  13.     int ret_status = EOF;  
  14.     char dir_name[2001];  
  15.     char file_name[2000];  
  16.     FILE *fp = NULL;  
  17.     char *work = NULL;  
  18.   
  19.     va_start(ap, fmt);  
  20.   
  21.     /* Warning: tmpfile() does not work well on Windows (MinGW) 
  22.      *          if user does not have write access on the drive where  
  23.      *          working dir is? */  
  24. #ifdef _WIN32  
  25.     /* file_name = G_tempfile(); */  
  26.     GetTempPath ( 2000, dir_name );  
  27.     GetTempFileName ( dir_name, "asprintf", 0, file_name );  
  28.     fp = fopen ( file_name, "w+" );  
  29. #else  
  30.     fp = tmpfile();   
  31. #endif /* _WIN32 */  
  32.   
  33.     if ( fp ) {  
  34.         int count;  
  35.   
  36.         count = vfprintf(fp, fmt, ap);  
  37.         if (count >= 0) {  
  38.             work = calloc(count + 1, sizeof(char));  
  39.             if (work != NULL) {  
  40.                 rewind(fp);  
  41.                 ret_status = fread(work, sizeof(char), count, fp);  
  42.                 if (ret_status != count) {  
  43.                     ret_status = EOF;  
  44.                     free(work);  
  45.                     work = NULL;  
  46.                 }  
  47.             }  
  48.         }  
  49.         fclose(fp);  
  50. #ifdef _WIN32  
  51.         unlink ( file_name );  
  52. #endif /* _WIN32 */  
  53.     }  
  54.     va_end(ap);  
  55.     *out = work;  
  56.   
  57.     return ret_status;  
  58. }  

 

虽然麻烦,但在没有vsnprintf时是个不错的应急方案。

重申一下,这只是近似的方案,并不一定和真正的asprintf功能一样。

 

problem 21 获取指定文件名(可能是相对路径)的完整目录名

和问题20一样,出现在lua-checker的代码中

http://code.google.com/p/lua-checker/

我的移植方案是用VC的C运行时库函数_fullpath和_splitpath来模拟dirname:

 

C代码  收藏代码
  1. #ifndef _MSC_VER  
  2. #include <libgen.h>           // For dirname()  
  3. #else  
  4.   
  5. #include <stdio.h>  
  6. #include <conio.h>  
  7. #include <stdlib.h>  
  8. #include <direct.h>  
  9.   
  10. static const char *dirname(const char *partialPath)  
  11. {  
  12.     static char full[1000] = {0};  
  13.     static char path_buffer[1000] = {0};  
  14.     static char drive[1000] = {0};  
  15.     static char dir[1000] = {0};  
  16.     static char fname[1000] = {0};  
  17.     static char ext[1000] = {0};  
  18.     static char fulldir[1000] = {0};  
  19.     if( _fullpath( full, partialPath, sizeof(full) ) != NULL )  
  20.     {  
  21.         _splitpath( full, drive, dir, fname, ext );  
  22.         strcpy(fulldir, drive);  
  23.         strcat(fulldir, dir);  
  24.     }  
  25.     else  
  26.     {  
  27.         strcpy(fulldir, "");  
  28.     }  
  29.     return fulldir;  
  30. }  
  31. #endif  

 

problem 22 只能读文件4KB以内的内容?

使用fopen的"r"模式,一次性读取4KB内容到char[](使用fread函数),发现4KB以外的内容都是0(没有完整地读出)。

正确的做法是使用"rb“模式。

 

problem 23 VC2008的char类型的无符号问题

因为char在旧版的C中充当BYTE类型来使用(unsigned char),但新版的VC2008实施强类型,char类型将被当作有符号数来处理,如果想把char当作无符号来使用,应该更改VC工程的属性,添加/J参数。

 

problem 24 long long 输出

 

C代码  收藏代码
  1. #include <stdio.h>     
  2.                     
  3. int main(void)  
  4. {     
  5.     long long mem = 123456789012;     
  6.     printf("mem=%ld\n",mem);     
  7.     exit(0);     
  8. }     
  9. //输出不正确呀,应该用什么转移符?  
  10.   
  11. print("mem=%lld\n",men);   

 

see http://blog.csdn.net/huangxb_csu/archive/2008/12/30/3648779.aspx

 

 

problem 25: 找不到strcasecmp

摘自

http://blog.csdn.net/chinacodec/archive/2010/01/03/5124977.aspx

 

C代码  收藏代码
  1. #ifdef _MSC_VER  
  2. #include <string.h>  
  3. #define strcasecmp stricmp  
  4. #define strncasecmp  strnicmp  
  5. #endif  

 

problem 26 : 使用SDL头文件时出现undefined reference to `WinMain@16' 

原因是SDL.h把main宏定义了,可以用nm或dumpbin检查.o文件的符号是否有_main(可以用grep过滤)

解决办法可以取消main的宏定义:

 

C代码  收藏代码
  1. #undef main  
  2. int main( int argc, char* argv[] ) {  

补注: 正确做法应该是使用libSDLmain.a的WinMain入口,方法是把链接参数中的-lmingw32提前到-lSDLmain之前,例如

写道
-lmingw32 -lSDLmain -lSDL

 

 

 

 

problem 27: drand48和srand48

Windows上可以简单地实现

 

C代码  收藏代码
  1. #ifdef _WIN32  
  2. #define drand48() (((float) rand())/((float) RAND_MAX))  
  3. #define srand48(x) (srand((x)))  
  4. #endif  

 或参考http://blog.csdn.net/jimmyblind/archive/2010/05/02/5550042.aspx

注意,对随机数取模是个不好的设计,因为取模得到序列的可能不够均匀。

 

 

problem 28: bcb6的“Call to function 'xxx' with no prototype”警告

对于空参数表的函数声明,必须指明为void,例如xxx(void);

 

(后续,待修改)

 

problem 29: 在Windows上使用MinGW+SWIG书写JNI

Windows上的JNI实际上是Java虚拟机调用原生dll的导出函数。

尝试使用Cygwin+SWIG生成JNI,但不成功(提示aborted)

但使用mingw则没有问题(可能是cygwin的dll造成JNI不可用)

需要注意的是最后编译dll时使用的参数-Wl,--add-stdcall-alias,见

http://www./tutorial.html

 

我尝试用手工Makefile编译JNI,编译工程是官方发布包中的swigwin-2.0.3\Examples\java\simple

方法如下:

 

1. 创建目录swigtest,把simple示例的代码都复制进去

 

2. 把jdk下的include文件(我的JDK头文件在

D:\java\jdk1.6.0_20\include

D:\java\jdk1.6.0_20\include\win32

)全部复制到目录swigtest(include\win32下的文件直接和include下的头文件放在一起)

这样做是因为,我在使用-I时无法指向这两个目录(原因不明)

 

3. 手工书写新的Makefile

(注意,我的javac在d:\java\jdk1.6.0_20\bin\javac.exe,所以指向mingw风格的目录/d/java/jdk1.6.0_20/bin/javac)

 

 

Makefile代码  收藏代码
  1. CC := gcc  
  2. LD := ld  
  3. RM := rm -f  
  4. SWIG := swig  
  5. OBJS := example.o example_wrap.o  
  6. CFLAGS := -I.  
  7. # -I/D/java/jdk1.6.0_20/include -I/D/java/jdk1.6.0_20/include/win32  
  8. # -I/cygdrive/d/java/jdk1.6.0_20/include   
  9.   
  10. JAVAC := /d/java/jdk1.6.0_20/bin/javac  
  11.   
  12.   
  13. all : example.dll java  
  14.   
  15. java :   
  16.     ${JAVAC} *.java  
  17.   
  18. example.dll : ${OBJS}  
  19.     ${CC} -shared ${CFLAGS} -Wl,--add-stdcall-alias -o $@ ${OBJS}  
  20.   
  21. # -mno-cygwin   
  22.   
  23. %.o : %.c  
  24.     ${CC} ${CFLAGS} -o $@ -c $<  
  25.       
  26. # exampleJNI.java  
  27. example_wrap.c : example.i  
  28.     ${SWIG} -o $@ -java $<  
  29.   
  30. clean :  
  31.     ${RM} *.o *.class *.dll example.java example_wrap.c exampleJNI.java  

 

然后运行:

> make clean all

> java runme

 

(补充说明:如果要编译64位的JNI动态库(因为64位JRE只能使用64位的dll动态库),需要使用-m64或-B参数生成64位dll,或者用TDM-GCC-64工具链(默认生成64位exe和dll))

 

 

problem 30 编译动态库和静态库

动态库:

gcc -shared -o <.dll文件> <.o文件>...

 

静态库:

ar rcs <.a文件> <.o文件> ...

(有时下面还可以对.a文件使用ranlib命令,但一般可以忽略不做)

 

 

problem 31  configure时输出.i文件检查宏展开后的编译错误

 

 

CFLAGS=-save-temps

 

see

http://code.google.com/p/memcached/issues/detail?id=111

 

problem 32  isspace错误

 

如果在cygwin中使用不经过类型转换的isspace
array subscript has type ‘char’

 

解决办法如下 

 

/* Avoid warnings on solaris, where isspace() is an index into an array, and gcc uses signed chars */
#define xisspace(c) isspace((unsigned char)c)

 

或者手工转换类型 

 

see

https://github.com/lindner/memcached/blob/master/util.c

http://code.google.com/p/memcached/issues/detail?id=111

 

类似的情况出现在cygwin的大部分isXXX函数

 

 

problem 33 printf系输出的乱码问题

 

 

C 使用wprintf,_tprintf 打印简体中文的方法 【Locale.h】

http://www.cnblogs.com/niuniu502/archive/2009/02/17/1392636.html

 

需要分两种情况考虑:

1. 非Unicode版

_ftprintf(stderr, _T("%S\n"), "你好吗");

2. Unicode版

#include <locale.h>

setlocale(LC_ALL, "");

_ftprintf(stderr, _T("%s\n"), _T("你好吗"));

 

注意,两种情况的%s的大小写含义是不一样的!

这一点在微软的文档中有详细说明——

就是说printf的%s是非Unicode字符串的占位符;

而wprintf的%s是Unicode字符串的占位符;

printf的%S是Unicode字符串的占位符;

而wprintf的%S是非Unicode字符串的占位符;

wprintf还需要setlocale才能正常在控制台中输出。

 

另外,出现乱码还可能是因为——参数个数不匹配

problem 34 VC6与MinGW的内联汇编。
有时需要在C中嵌入汇编以获取底层硬件信息。
例如在mingw中测试CPU频率
C代码  收藏代码
  1. static long CPUClock __asm__("CPUClock") = 0;  
  2.   
  3. ...  
  4.   
  5.   
  6.         asm (  
  7.             ".intel_syntax noprefix\n\t"  
  8.             "RDTSC\n\t"  
  9.             "MOV        [CPUClock],     EAX\n\t"  
  10.             ".att_syntax\n"  
  11.         );  
  12.         Sleep(1000);  
  13.         asm (  
  14.             ".intel_syntax noprefix\n\t"  
  15.             "RDTSC\n\t"  
  16.             "SUB        EAX,            [CPUClock]\n\t"  
  17.             "MOV        [CPUClock],     EAX\n\t"  
  18.             ".att_syntax\n"  
  19.         );  
  20.         CPUClock /= 1000000;  
限制是,
1) 可以嵌入C变量,但不能与寄存器的名称有冲突(2014/01/23注:__asm__后面的引号中的汇编名称必须为大写,否则可能编译出错)
2) 默认不是intel格式,所以开头要用宏指令声明为intel语法。
大部分情况下最好用GNU风格的汇编,
但有时需要移植Win32的汇编时可以考虑写成上面不伦不类的样子。
对应的vc6内嵌汇编是:
see also:
C代码  收藏代码
  1. __asm  
  2. {  
  3.     RDTSC  
  4.     MOV     [CPUClock],     EAX  
  5. }  
  6.   
  7. Sleep( 1000 );  
  8.   
  9. __asm  
  10. {  
  11.     RDTSC  
  12.     SUB     EAX,            [CPUClock]  
  13.     MOV     [CPUClock],     EAX  
  14. }  
  15.   
  16. CPUClock /= 1000000;  
在VC6中汇编内嵌的C变量只要声明为函数的局部变量即可。
C代码  收藏代码
  1. long CPUClock       = 0;  
problem 35: Win32程序中转至发布版时出现控件不能显示的情况。
那是因为使用CreateWindowEx这类函数创建控件时返回0。
原因是编译时出现警告:
LINK : warning LNK4089: all references to "comdlg32.dll" discarded by /OPT:REF
而控件类的创建是在comdlg32.dll中进行,忽略它将导致控件类不加载,引发错误。
解决办法是调用InitCommonControls(需要增加链接comctl32.lib)
同样原因,在使用RichEdit20A前要LoadLibrary("RICHED20.DLL")
problem 36: mingw gcc 4需要动态链接libgcc_s_dw2-1.dll
怀疑mingw的开发者想加入一些全局的功能(?),例如strace。
解决办法是在gcc后面使用-static-libgcc编译开关。
如果用TDM-GCC则没有此问题。
转自:
MinGW升级到4.5.2生成的exe需要libgcc_s_dw2-1.dll和libstdc++-6.dll ? 写道
-static-libgcc在 gcc/g++ 或 ld 中加上这个参数, 就可以不用 libgcc_s_dw2-1.dll
-static-libstdc++在 g++ 或 ld 中加上这个参数, 就可以不用 libstdc++-6.dll
-static在 gcc/g++ 或 ld 中加上这个参数, 對所有的库都会采用静态链接的方式

problem 37: 如何修改CMakeLists.txt,使生成的VC工程可以链接C运行时库的多线程静态版(把/MD换为/MT)
例如,llvm-2.7的源码中的CMakeLists.txt有一个对MSVC的判断:
if( MSVC )
  # List of valid CRTs for MSVC
  set(MSVC_CRT
    MD
    MDd)
  set(LLVM_USE_CRT "" CACHE STRING "Specify VC++ CRT to use for debug/release configurations.")
  add_llvm_definitions( -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS )
  add_llvm_definitions( -D_SCL_SECURE_NO_WARNINGS -DCRT_NONSTDC_NO_WARNINGS )
  add_llvm_definitions( -D_SCL_SECURE_NO_DEPRECATE )
  add_llvm_definitions( -wd4146 -wd4503 -wd4996 -wd4800 -wd4244 -wd4624 )
  add_llvm_definitions( -wd4355 -wd4715 -wd4180 -wd4345 -wd4224 )
  # Suppress 'new behavior: elements of array 'array' will be default initialized'
  add_llvm_definitions( -wd4351 )
  if (NOT ${LLVM_USE_CRT} STREQUAL "")
    list(FIND MSVC_CRT ${LLVM_USE_CRT} idx)
    if (idx LESS 0)
      message(FATAL_ERROR "Invalid value for LLVM_USE_CRT: ${LLVM_USE_CRT}. Valid options are one of: ${MSVC_CRT}")
    endif (idx LESS 0)
    add_llvm_definitions("/${LLVM_USE_CRT}")
    message(STATUS "Using VC++ CRT: ${LLVM_USE_CRT}")
  endif (NOT ${LLVM_USE_CRT} STREQUAL "")
后面加上这样的句子:
foreach(flag_var
        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
   if(${flag_var} MATCHES "/MD")
      string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
   endif(${flag_var} MATCHES "/MD")
endforeach(flag_var)
这里使用了regex replace把所有flags的/MD替换为/MT。
problem 38: strdup or _strdup ?
see
如果在Windows下,建议用_strdup,
如果在Linux下,建议用strdup。
实际上这个函数不是太好,建议最好别用。
20160707:如果提示没有定义,可以用这个函数替换:
char *my_strdup(const char *str) {
    size_t len = strlen(str);
    char *x = (char *)malloc(len+1); /* 1 for the null terminator */
    if(!x) return NULL; /* malloc could not allocate memory */
    memcpy(x,str,len+1); /* copy the string into the new buffer */
    return x;
}
参考:http:///questions/5573775/strdup-error-on-g-with-c0x
problem 39: ISO 'for'内的局部变量
例如在for(int i=1; i < 10; i++)这样的循环外继续使用变量i会导致cygwin警告
提示添加-fpermissive
所以最好把int i移到循环之前,以兼容不同的编译器。
problem 40: cygwin用new创建变长的字符串可能未初始化为0
char *buffer = new char[size + 1];
buffer[size] = 0;
最后一句是确保末尾的0(只有Cygwin有必要)
VC6和Linux可以不写最后那句buffer[size] = 0;,
是因为new已确保整个数组内容已清零。
problem 41: VC6编译时出现internal heap limit reached; use /Zm to specify a higher limit
原因是代码中出现很大的常量数组时:解决办法是在工程右键->Settings->C/C++下方添加/Zm1500
MinGW没有此问题,但编译时较慢。
problem 42: 使用g++编译c++代码时无法使用stricmp
解决方法:C++不使用stricmp,而是使用strcasecmp(#include <cstring>),
see
problem 43: 
为什么vc2008编译就提示找不到msvcr90d.dll
方法:
* 关闭增量链接(配置属性->链接器->常规)
或者:
* Project Properties -> Manifest Tool-> Use FAT32 Work-around 为Yes重新编译
参考自:http://bbs.csdn.net/topics/220055015

 problem 44:

getopt和getopt_long重入问题。

一般程序只能调用一次getopt或getopt_long,如果第二次调用,将无法获取参数信息。

解决办法是在调用之前对optreset和optind赋值为1(这两个变量声明在getopt.h中)

  optreset = 1;

  optind = 1;

 

 

problem 45:

fwrite返回值判断出错问题和原因

//代码只是大概意思,可能有误,仅参考用

if (fwrite(buffer, sizeof(unsigned char), nRead, file) != (size_t)(nRead)) {

   fprintf(stderr, "error : %s .\n", strerror(errno));

}

如果出现不等于的情况(fwrite出错),与socket(网络套接字)的写入不同的是,不是因为写入数据不全,而是因为其它原因(例如,从strerror可以知道,因为磁盘空间不足),不要主观臆断。

另外,nRead似乎有范围限制(受限于size_t的大小(注:理论上32位的最大值是2GB,但实际读入和写出的最大值跟fread和fwrite实现有关,参考http:///questions/18879410/fread-number-of-bytes-limit

http:///questions/730709/2gb-limit-on-file-size-when-using-fwrite-in-c

))

 

problem 46:

如果在模板参数中引用std标准库内的类型,必须加typename,否则编译可能会出错。

例如:假设vectorEx类继承std::vector,则

Cpp代码  收藏代码
  1. template<class T> bool vectorEx<T>::erase(T t) {  
  2.     iterator it = begin();  

 

 要改写成:

 

Cpp代码  收藏代码
  1. template<class T> bool vectorEx<T>::erase(T t) {  
  2.     typedef typename vectorEx<T>::iterator iterator;  
  3.     iterator it = vector<T>::begin();  

 

 而类内部的声明

Cpp代码  收藏代码
  1. pair<iterator, bool> insert(T t);  

 

 (可能)需要改写成(否则iterator可能会报找不到定义的编译错误,

相当于写成

std::pair<typename vectorEx<T>::iterator, bool> insert(T t)

注意typename的位置:

 

Cpp代码  收藏代码
  1. typedef typename vectorEx<T>::iterator iterator;  
  2. typedef typename vectorEx<T>::const_iterator const_iterator;  
  3. typedef typename vectorEx<T>::size_type size_type;  
  4. pair<iterator, bool> insert(T t);  

 

 

problem 47:链接exe时出现下划线符号强制链接成@符号

写道
Warning: resolving _Sleep by linking to _Sleep@4
Use --enable-stdcall-fixup to disable these warnings
Use --disable-stdcall-fixup to disable these fixups

这个警告虽然会成功生成exe文件,但程序可能会崩溃。那是因为编译器不知道windows api函数Sleep是stdcall函数而非普通c函数,最好确保添加头文件以消除这个警告

 

C代码  收藏代码
  1. #define WIN32_LEAN_AND_MEAN  
  2. #include <windows.h>  

 

(2014/08/16)

 problem 48. -mthreads与mingwm10.dll

http://tkamogashira.users./sodan/tips/mingwcross.html

(20140912)

简单来说,如果使用-mthreads编译程序,就不能完全静态编译(需要动态链接mingwm10.dll)以保证多线程下的异常处理是正常的(好像还是因为兼容旧版本Windows,所以可以认为是mingw一个不完美的bug)。

这个问题出现在静态编译qt 4.3.5的时候(在configure的时候关闭C++异常机制可以避免链接mingwm10.dll)

一般的程序不使用C++异常或者不使用-mthreads就不会遇到这个问题。

 

20141216:

problem 49:unresolved external symbol __iob

参考:

http://blog.sina.com.cn/s/blog_5d890d070100fpj1.html

 

写道
1、缺少libc.lib
解决这个问题的方法是去掉链接到libc.lib,具体地点:项目-〉属性-〉配置属性-〉链接器-〉忽略特定库。
2、unresolved external symbol __iob
这个__iob找不到的问题费 了我大部分的时间。跟踪到stdio.h文件,发现那里有个关于iob的宏,终于搞定。加入一句话到.cpp文件中:extern "C" { FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]}; }

 

20141227:

problem 50:匿名结构体

如果匿名结构体的形式是(非标准写法)

C代码  收藏代码
  1. struct B{  
  2.     struct A; //注意,这里不是指针变量也不是结构体变量,而是结构体类型名(假设已声明过)  
  3.     int b;  
  4. };  

 等效于(下面是gcc标准写法)

 

C代码  收藏代码
  1. struct B{  
  2.     struct A{  
  3.         int a;  
  4.     }; //gcc写法,不能用于VC++  
  5.     int b;  
  6. };  

 

gcc需要在gcc后添加编译参数-fms-extensions

visual studio需要添加/wd4201 /wd4996参数

C4201: nameless struct/union,

C4996: This function or variable may be unsafe.

这样做是兼容微软的匿名结构体语法

C代码  收藏代码
  1. struct A{  
  2.     int a;  
  3. };  
  4. struct B{  
  5.     struct A; //VC++写法,可以用于gcc,但需要设置编译器参数  
  6.     int b;  
  7. };  

    匿名结构体的作用是允许struct B在指针取成员的语法上拥有struct A的所有成员(前提是不能有相同名字的其他成员),同时struct B*可以安全地强制转换成struct A*,实现类似C++的继承特性。

    还有类似的做法是struct B拥有struct A*(是指针而非结构体),不过匿名结构体的好处是内存分配只需要做一次 。

详细请参考:

https://github.com/teejii88/mgui

http://pingf./categories/4252/posts

 

 

 

20150808:

problem 51:字节对齐写法

(参考mruby)

 

(1)gcc写法和vc写法(不含VC6),注意是作为变量修饰符使用

const uint8_t

#if defined __GNUC__

__attribute__((aligned(4)))

#elif defined _MSC_VER

__declspec(align(4))

#endif

k[] = {...}

 

(2)VC6写法(注意,不是修饰符,是pragma命令)

#ifdef _MSC_VER

#pragma pack(push)

#pragma pack(4)

#endif

...

 

#ifdef _MSC_VER

#pragma pack(pop)

#endif

 

 

(20160311)

problem 52.error: '::swprintf' has not been declared的解决

http://blog.sina.com.cn/s/blog_4f183d9601015zls.html

解决办法:-U__STRICT_ANSI__

 

(20161008)

__builtin_函数在某些版本的mingw中不存在,例如__builtin_unreachable(参考:jerryscript)

Emulating GCC's __builtin_unreachable?

http:///questions/6031819/emulating-gccs-builtin-unreachable

GCC内建函数

https://gcc./onlinedocs/gcc/Other-Builtins.html

 

 (20170222)

获取宏定义(随便创建一个c文件然后传入参数-E -dM)

 gcc -E -dM test.cpp | grep MINGW

参考:(原文是gcc -posix -E -dM - </dev/null)

http://blog.csdn.net/cywosp/article/details/10730931

 

 (20170315)

还有一种办法是强制加入头文件 -include cstddef或者修改源代码:include<cstddef>或using std::ptrdiff_t // ptrdiff_t does not name a type造成编译错误 - klarclm的专栏 - 博客频道 - CSDN.NET

http://blog.csdn.net/klarclm/article/details/8565484

 

修改:

2016-03-11 添加problem 52

2015-08-08 添加problem 51

2014-12-27 添加problem 50

2014-12-16 添加problem 49

2014-01-28 修改problem 26

2014-01-23 添加problem 46、47

2013-05-30 添加problem 45

2013-05-25 添加problem 44

2013-04-18 添加problem 43

2012-07-04 添加problem 41, 42

2011-12-25 添加problem 38, 39, 40

2011-12-02 添加problem 37

2011-11-21 添加problem 36

2011-11-19 添加problem 35

2011-11-10 添加problem 34

2011-07-27 修改problem 20

2011-07-14 添加problem 33

2011-05-01 添加problem 31、32

2011-04-29 增加problem 29、30

2011-04-25 增加开头的参考链接

2011-04-23 补充problem 28

2011-04-10 补充problem 25、26、27

2011-03-27 补充problem 24

2011-02-01 补充problem 22、23

2011-01-25 补充problem 20、21

2010-12-21 补充problem 19

2010-12-07 补注WSAPoll的问题

2010-11-01 补充problem 18

2010-10-31 补充problem13:WSAPoll

2010-09-23 补充problem 15,16,17.来自于mysql++编译的移植问题。

2010-09-08 补充problem13中关于drizzle源码包中的poll实现

2010-09-01 补充problem13使用msysDVLPR的情况

2010-08-28 增加problem12, 13, 14

2010-08-14 修改了problem11,补充了problem7和problem5

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多