1 Star 0 Fork 0

Jesse Jin / blog

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
lazarus001.md 7.75 KB
一键复制 编辑 原始数据 按行查看 历史
Jesse Jin 提交于 2023-05-23 23:13 . [new]ctypes里的bug?

ctypes里的bug?

起因

以前使用Delphi调用海康SDK时,专门改写过HCNetSDK.h,当时大部分桌面应用还都是32位的,毕竟64位还没彻底普及开(即便现在,还是有一部分桌面考虑兼容性依然是32位)。后来也搞过64位版的,编译没问题,运行就不成功。虽然没成功,但心里还是清楚这基本上是数据类型的问题,由于对64位了解不多,也就一直搁置着。

Lazarus之后,又搞过一次64位版,还是没成功。后来知道有ctypes这个单元,也知道这是专门针对c语言数据类型的,但一直没去看过。近来又想起这个事,就想一探究竟。

直接看源码,其实就是给pascal的数据类型取了个c的别名。要想了解透彻,自已撸码跑一下还是很有必要的:

program test;

uses
  SysUtils,
  ctypes;

begin
  writeln(Format('%-16s%s', ['type', 'size']));
  writeln('--------------------');
  writeln(Format('%-16s%d', ['cint8', SizeOf(cint8)]));
  writeln(Format('%-16s%d', ['cuint8', SizeOf(cuint8)]));
  writeln(Format('%-16s%d', ['cchar', SizeOf(cchar)]));
  writeln(Format('%-16s%d', ['cschar', SizeOf(cschar)]));
  writeln(Format('%-16s%d', ['cuchar', SizeOf(cuchar)]));
  writeln(Format('%-16s%d', ['cint16', SizeOf(cint16)]));
  writeln(Format('%-16s%d', ['cuint16', SizeOf(cuint16)]));
  writeln(Format('%-16s%d', ['cshort', SizeOf(cshort)]));
  writeln(Format('%-16s%d', ['csshort', SizeOf(csshort)]));
  writeln(Format('%-16s%d', ['cushort', SizeOf(cushort)]));
  writeln(Format('%-16s%d', ['cint32', SizeOf(cint32)]));
  writeln(Format('%-16s%d', ['cuint32', SizeOf(cuint32)]));
  writeln(Format('%-16s%d', ['cint64', SizeOf(cint64)]));
  writeln(Format('%-16s%d', ['cuint64', SizeOf(cuint64)]));
  writeln(Format('%-16s%d', ['clonglong', SizeOf(clonglong)]));
  writeln(Format('%-16s%d', ['cslonglong', SizeOf(cslonglong)]));
  writeln(Format('%-16s%d', ['culonglong', SizeOf(culonglong)]));
  writeln(Format('%-16s%d', ['cbool', SizeOf(cbool)]));
  writeln(Format('%-16s%d', ['cint', SizeOf(cint)]));
  writeln(Format('%-16s%d', ['csint', SizeOf(csint)]));
  writeln(Format('%-16s%d', ['cuint', SizeOf(cuint)]));
  writeln(Format('%-16s%d', ['clong', SizeOf(clong)]));
  writeln(Format('%-16s%d', ['cslong', SizeOf(cslong)]));
  writeln(Format('%-16s%d', ['culong', SizeOf(culong)]));
  writeln(Format('%-16s%d', ['csigned', SizeOf(csigned)]));
  writeln(Format('%-16s%d', ['cunsigned', SizeOf(cunsigned)]));
  writeln(Format('%-16s%d', ['csize_t', SizeOf(csize_t)]));
  writeln(Format('%-16s%d', ['cfloat', SizeOf(cfloat)]));
  writeln(Format('%-16s%d', ['cdouble', SizeOf(cdouble)]));
  writeln(Format('%-16s%d', ['clongdouble', SizeOf(clongdouble)]));
  Readln();
end.

做为对比,c的也来一下:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

int main(int argc, char *argv[]) {
	printf("%s\t %d\n","int8_t",sizeof(int8_t));
	printf("%s\t %d\n","uint8_t",sizeof(uint8_t));
	printf("%s\t %d\n","char",sizeof(char));
	printf("%s\t %d\n","signed char",sizeof(signed char));
	printf("%s\t %d\n","unsigned char",sizeof(unsigned char));
	printf("%s\t %d\n","int16_t",sizeof(int16_t));
	printf("%s\t %d\n","uint16_t",sizeof(uint16_t));
	printf("%s\t %d\n","short",sizeof(short));
	printf("%s\t %d\n","signed short",sizeof(signed short));
	printf("%s\t %d\n","unsigned short",sizeof(unsigned short));
	printf("%s\t %d\n","int32_t",sizeof(int32_t));
	printf("%s\t %d\n","uint32_t",sizeof(uint32_t));
	printf("%s\t %d\n","int64_t",sizeof(int64_t));
	printf("%s\t %d\n","uint64_t",sizeof(uint64_t));
	printf("%s\t %d\n","long long",sizeof(long long));
	printf("%s\t %d\n","signed long long",sizeof(signed long long));
	printf("%s\t %d\n","unsigned long long",sizeof(unsigned long long));
	printf("%s\t %d\n","bool",sizeof(bool));
	printf("%s\t %d\n","int",sizeof(int));
	printf("%s\t %d\n","signed int",sizeof(signed int));
	printf("%s\t %d\n","unsigned int",sizeof(unsigned int));
	printf("%s\t %d\n","long",sizeof(long));
	printf("%s\t %d\n","signed long",sizeof(signed long));
	printf("%s\t %d\n","unsigned long",sizeof(unsigned long));
	printf("%s\t %d\n","signed",sizeof(signed));
	printf("%s\t %d\n","unsigned",sizeof(unsigned));
	printf("%s\t %d\n","size_t",sizeof(size_t));
	printf("%s\t %d\n","float",sizeof(float));
	printf("%s\t %d\n","double",sizeof(double));
	printf("%s\t %d\n","long double",sizeof(long double));
	return 0;
}

分别用32位64位编译运行,然后,然后就凌乱了~

// Lazarus              | // c
// type    32bit 64bit  | // type           32bit 64bit
----------------------- | ------------------------------
cint8        1     1    | int8_t              1     1
cuint8       1     1    | uint8_t             1     1
cchar        1     1    | char                1     1
cschar       1     1    | signed char         1     1
cuchar       1     1    | unsigned char       1     1
cint16       2     2    | int16_t             2     2
cuint16      2     2    | uint16_t            2     2
cshort       2     2    | short               2     2
csshort      2     2    | signed short        2     2
cushort      2     2    | unsigned short      2     2
cint32       4     4    | int32_t             4     4
cuint32      4     4    | uint32_t            4     4
cint64       8     8    | int64_t             8     8
cuint64      8     8    | uint64_t            8     8
clonglong    8     8    | long long           8     8
cslonglong   8     8    | signed long long    8     8
culonglong   8     8    | unsigned long long  8     8
cbool        4     4    | bool                1     1
cint         4     4    | int                 4     4
csint        4     4    | signed int          4     4
cuint        4     4    | unsigned int        4     4
clong        4     4    | long                4     4
cslong       4     4    | signed long         4     4
culong       4     4    | unsigned long       4     4
csigned      4     4    | signed              4     4
cunsigned    4     4    | unsigned            4     4
csize_t      4     8    | size_t              4     8
cfloat       4     4    | float               4     4
cdouble      8     8    | double              8     8
clongdouble  12    8    | long double         12    16

cbool的差异大概知道是怎么回事,这clongdouble是个什么鬼?难道是bug?

先说cbool,在win平台上,使用cbool类型的很少,大多数都是用微软的BOOL,而32位平台上的BOOL确实是4B64位的没研究过,想来为了可移植性应该也是4B

再说clongdouble,从感官上讲,64位类型比32位要大才是正常的,而Lazarusclongdouble64位32位还小,似乎是有问题的。

深深地怀疑这是个bug,然后提了Issues。大概一个小时后,大佬maynard philbrook回复了:

From what I know, and that isn't much. the Fpc 64-bit compiler does not use the Extended float type because it doesn't use the FPU, just the 64-bit registers that exist to performs the double math.

From what I understand it was decided that way because function API calls in the OS do it this way so local support for FPU isn't there.

But is used in the 32-bit target.

Good luck and have a good day.

大意是说:fpc64位编译器不使用扩展浮点类型,因为它不使用FPU浮点处理单元,只使用用于执行双精度数学运算的64位寄存器,这也是出于考虑到操作系统的API是这么调用的。但是32位的编译器还是使用FPU的。

呃~这一下就扯到编译器上了,完全是咱的知识盲区嘛!既然大佬都这么说了,而且也这么多年了,肯定是不会错的,那么,就当是长了次见识了吧!

1
https://gitee.com/afrusrsc/blog.git
git@gitee.com:afrusrsc/blog.git
afrusrsc
blog
blog
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891