【杂谈指针】- 指针的移动

刚刚在群里看到一个这样的问题

MonoPixel: PByte;

Inc(Integer(MonoPixel));这个在32位下没问题,为啥64位不能编译呢?

 

咋一看,以为是把里面的值进行累加,后来一想应该是移动一下指针。

对于这种移动指针的做法有两个错误:

第一个是用了Integer,来转换指针如果在32位下面显然是没有问题的,但是如果是64位,指针是64位,显然再用Integer是错误的。

第二个转换成Ineger后加一,那就相当于整数值 + 1,在PByte时没有问题,因为Byte也是一个字节。但是如果是PInteger指针就会出现错误。

 

我们来看下代码:

如果是PInteger下面应该怎么样做:

var
  p, d:PInteger;
  x : array [0..10] of Integer;
begin
  x[5] := 120;
  p := @x;
  d := p;
  Inc(d, 5);

 

 

首先所有的指针都是一个整数值

image

可以看到如果用inc移动指针,并且会按照指针的类型进行累加,上面PInteger类型Inc后是增加的SizeOf(Integer)。指向数组的下一个元素。

如果单纯的转换成整数来 + 1会 指针的值就是$12EA75显然不是指向下一个元素。当然你取到的值也是错误的。如下面的图

image

显然d^不是我们想要的数据。

除了用inc,也可以这样做,下面的做法也是正确的。

image

请操作指针的朋友们注意啦。

*以上代码在XE6下面测试运行

 

*注意没有IntPtr类型的可以自己定义下类型

type

   IntPtr = cardinal

 

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

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

VirtualBox与VMWare网络冲突

VirtualBox安装一个XP后,发现老是上不到网,怎么折腾都不行,

后来发现设备管理器中 vmware accelerated amd pcnet adapter #2显示黄色感叹号

不对呀,这是VirtualBox怎么是vmware的东西,后来百度后,发现禁用vmware网卡,

image

也把VirutalBox 的网卡去掉了vmware bridage Protocol ,重启N次,里面还是那个vm的网卡,

后来百度这个词(vmware accelerated amd pcnet adapter)发现了这篇文章

http://vbox.blogcn.com/6

 

前几日分享了Virtualbox快照备份恢复系统的方法,但是发现从备份中恢复的系统似乎有很多问题,比如经常出现.DLL错误,出现mysql无法启动等问题,搞来搞去,真的很麻烦~~~

搞的都无语了~~

因为网速不给力,所以就在晚上重新下载了个XP ISO,还是雨林木风的~~今天安装好了之后发现,又出现vmware accelerated amd pcnet adapter显示黄色感叹号,真的是没有一件顺利的事情~~NND.

找了好多驱动没弄好,最后一不小心被我发现了解决的办法~~

在更新网卡驱动的地方右键--然后选择更新驱动,然后选择不搜索,自己安装,然后选择AMD的那个网卡即可,这样就能正常上网了,有浪费了我半个多小时,哎,我就想好好用下虚拟机,有这么困难么~~~真的搞的没办法~~~

终于搞定了

虚拟机的网络设定

image

关于SimpleMsgPack中swap引发的问题大端法和小端法研究笔记

今天diocp裙中[珠海]-芒果反应了一个关于SimpleMsgPack的问题

msgPack.AsFloat = 2.507182;

经过编码再解码后,会直接触发异常。

 

因为msgPack的标准,在打包的数据是大端法IEEE 754

下面是msgPack的标准说明

Float format family stores a floating point number in 5 bytes or 9 bytes.
float 32 stores a floating point number in IEEE 754 single precision floating point number format:
+--------+--------+--------+--------+--------+
|  0xca  |XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX
+--------+--------+--------+--------+--------+

float 64 stores a floating point number in IEEE 754 double precision floating point number format:
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  0xcb  |YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
where
* XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX is a big-endian IEEE 754 single precision floating point number
* YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY_YYYYYYYY is a big-endian
  IEEE 754 double precision floating point number

 

小端法变大端法把自己顺序调整下就好了

在SimpleMsgPack中有一个这样的函数,可以对Double类型的数据进行交换字节数。

procedure swap64Ex(const v; out outVal);
begin
  // 7F F5 B8 6F B5 0E 04 40

  // 40 04 0E B5 6F B8 F5 7F
  PByte(@outVal)^ := PByte(IntPtr(@v) + 7)^;
  PByte(IntPtr(@outVal) + 1)^ := PByte(IntPtr(@v) + 6)^;
  PByte(IntPtr(@outVal) + 2)^ := PByte(IntPtr(@v) + 5)^;
  PByte(IntPtr(@outVal) + 3)^ := PByte(IntPtr(@v) + 4)^;
  PByte(IntPtr(@outVal) + 4)^ := PByte(IntPtr(@v) + 3)^;
  PByte(IntPtr(@outVal) + 5)^ := PByte(IntPtr(@v) + 2)^;
  PByte(IntPtr(@outVal) + 6)^ := PByte(IntPtr(@v) + 1)^;
  PByte(IntPtr(@outVal) + 7)^ := PByte(@v)^;
end;

然后我重载了一些函数 这个函数对传入的Double进行交换字节然后返回Double类型

function swap(v:Double): Double; overload;
begin
  swap64Ex(v, Result);
end;

 

上面这个浮点数据 2.507182,经过交换后 如果仍然用Double类型来存放会是一个NaN, 会触发一个无效的浮点型数据的异常。因为不符合小端法的IEEE规则。

经过稍微修改后正常

function swap(v:Double): Int64; overload;
begin
  swap64Ex(v, Result);
end;

返回的值用Int64来存放这样就好了。

 

注意不要把一个不是Double类型的数据直接强制转换成Double类型,因为Double是有标准字节格式的,当然Single一样。

 

感谢,qdac-swish, 小白一起帮忙验证推理。

【MyBean调试笔记】关于单元的释放顺序

【概述】

DEMO提交人:惠商软件  2508696439

问题描述:MDIConsole, DEMO如果Forms单元引用顺序放在mybean.console.pas文件之后如下图所示时:

image

创建同一EXE内的MDI子插件并显示,在不关闭MDI子窗体的情况下,关闭主EXE时,会造成关闭时产生访问违规错误。

image

【调试过程】

看了问题,能重现,能重新的问题就不算什么问题了,一定可以找到原因的,开启debug dcus后,发现错误停留产生时,停留在Screen.FSaveFocusedXXX这一句。调试发现果然Screen为nil了。

(PEV87O}1LU$O[ESGWQ_R_K

 

【问题分析】

mybean在创建插件TComponent子插件时会传入beanFactory.VclOwners, 这样在程序关闭时,清理类工厂时,会释放他,并清理他的子组件,达到自动清理的插件的目的,因为getBean的插件没有手动关闭,是等待清理beanFactory时进行清理的,清理的时候,Screen已经被清理,所以产生了该错误。

我们看看工程文件的引用顺序

program MDIConsole;

uses
  FastMM4,
  FastMM4Messages,

  mybean.console,
  mybean.core.beanFactory,

  Forms,

上面代码来看是会先清理Forms,然后再清理mybean.console,和mybean.core.beanFactory单元,但是因为mybean.core.beanFactory里面引用了Forms单元,所以清理顺序变成了

1.mybean.core.beanFactory,

2.Forms,

3.mybean.console,

 

mybean.console单元中管理了所由的类工厂插件接口,因为类工厂是通过接口来决定生命周期的,所以在清理mybean.console单元的时候,才会释放最后一个工厂接口的引用,也就是释放vclOwners和他的子插件,这个时候application和screen实例都已经被释放了。所以procedure TCustomForm.BeforeDestruction;中访问Screen才会引发异常。

现在来优化下mybean的核心类。

mybean.core.beanFactory和mybean.console单元中都引用Forms单元,这样不管你顺序怎么调整,都让Forms单元成为在这两个单元后面。然后在mybean.core.beanFactory被清理时,清理工厂接口资源。

使顺序变成这样

1.mybean.core.beanFactory,

2.mybean.console,

3.Forms。

【MyBean调试笔记】接口的使用和清理

【DEMO信息】

有问题的DEMO, 由芒果提交

【问题描述】

双击Tab页面关闭页面和插件的时候出现AV异常

image

【问题调试】

我们在调试的时候出现这个错误时断点停在这里

image

可以看到停留在这个位置@IntfClear,指针清理的位置

image

好我们来调试下这个过程,跟一下是什么时候出现的, 在end 处下个断点后切换到cpu页,我们看到在ret之前调用了一过程,这个地址应该是做一些清理工作后然后返回到调用者地址,

`TDZCGURW[(RGU7B72)5CNY

跟进去后,一会就跳到错误的界面,可以说明在清理时出现的,这个时候我们来看看这段代码

复制代码

procedure TfrmMain.pgcMainMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
  lvPluginForm: IPluginForm;
  lvTabShtEx:TTabShtEx;
begin
  // 左键点击并且双击
  if (Button = mbLeft) and (ssDouble in Shift) then
  begin
    Index := pgcMain.IndexOfTabAt(X, Y);
    if Index >= 0 then
    begin
      lvTabShtEx := TTabShtEx(pgcMain.Pages[Index]);
      lvPluginForm := lvTabShtEx.PluginForm;
      if Application.MessageBox('确认要关闭画面吗?', '询问', MB_OKCANCEL + MB_ICONQUESTION) = IDCANCEL then
        Exit;
      lvPluginForm.freeObject;
      pgcMain.Pages[Index].Free;
    end;
  end;
end;

复制代码

这段代码中有一个lvPluginForm为接口IPluginForm变量, 过程在退出时会执行lvPluginForm := nil和其他一些资源的清理工作,清理的时候会触发对象的__release方法,但是我们看到这个对象已经释放掉了,然后在进行清理的时候出现了上面看到的访问违规的错误。

【问题解决】

找到出现问题的根本,解决起来就很快了,尽量不要等到过程清理时在去清理你的资源,特别是可能访问不存在的资源。在end;之前 加一句lvPluginForm := nil;这样就好了

分类: [MyBean说明书]

radxa-折腾系统ubuntu

想想今天从公司带了个键盘回来,继续折腾了下radxa板子,先折腾上ssh,听波哥的先折腾ssh。接上键盘,鼠标。

 

进入系统,rock用户,用b2andriod切换到了一次andriod挺正常,又切换回ubuntu,把无线连上去了, 百度下什么是ssh…

 

ssh,总的来说ssh是安全的可以让你远程做很多事情,好吧原来是这样,怎么装ssh?

sudo apt-get install openssh-server

啥意思?在哪里输入?

百度一下

ctrl + alt + t,进入命令模式

输入上面命令

开始安装了

装完后, 然后确认sshserver是否启动了:(或用“netstat -tlp”命令)

ps -e | grep ssh

http://www.cnblogs.com/chen1987lei/archive/2010/12/02/1894768.html

 

启动好后,然后在笔记本上面弄个ssh客户端

下载了一个MobaXterm_v7.3 可以通过ssh连接上ubuntu了。发现不能用root登陆ssh,要百度下

修改root 的密码

sudo passwd root

修改成功后,ssh还是不能登陆,波哥说要加入ssh配置

百度

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

 

$ sudo vi /etc/ssh/sshd_config

找到PermitRootLogin no一行,改为PermitRootLogin yes

各种不适用来了,反人类的vi编辑器(问了别人才知道vi是编辑器)

上面是说用vi 编辑sshd_config文件

幸好有猫叔和洞主指导…

输入上面命令后i进入编辑模式,然后找到

开始是

PermitRootLogin without-password

改成

PermitRootLogin yes

shift + “:”

输入wq!;保存退出

重启ssh,搞定

root可以登陆了,试一下reboot,可以重启

 

x!也是保存退出

q!是不保存退出

….听说vi是最优秀的编辑器。。。 以后我能适用么….

radxa-折腾第一步-刷机

 

我的电脑环境是:win64位,

板子回来是andriod的系统。

首先的装驱动, 下载固件

可以点击查看这篇文章

http://www.qdac.cc/?p=949

 

我是下载的这个固件radxa_rock_pro_dual_boot_20141022_update.zip

 

解压后里面有新的刷机工具

 

安装驱动

如果你已经安装好了USB驱动,请跳过此步骤。

使用RK Driver Assistant tools安装

在此安装过程中不需要连接Rockchip设备,只需要下载并解压RKDriverAssistant.zip,然后在RKDriverAssistant目录下的DriveInstall.exe上双击运行即可。 如果你之前为其他Rockchip设备安装过Rockchip USB驱动,确保首先点击”Uninstall Driver”。

RK Driver Assistant Install Uninstall.jpg

 

这是板子的图

 

 

官方的进入刷机模式帖子

http://wiki.radxa.com/Rock/Loader_mode/zh_cn

我折腾很久没折腾好,后来还是在群里问了。

 

第一个是在开机状态下<OTG线接电脑,打开刷机软件>

recovery key<长安> –>reset key<关掉后就可以松开> –>然后按Power。这个时候就进入了刷机状态。

 

第二种方法,关电源

按住recovery key 然后插线<OTG连接电脑> 就进入刷机状态。

 

好了可以用刷机工具写入固件了

 

密码是rock<没键盘…还没测试>

【DIOCP3-说明书】监控面板说明

IV](4]8GMYH)GSB9~A])TRN

发送队列 sending Queue: 

    push 任务压入<投递的发送任务>,

    pop 任务取出<投递到IOCP队列时弹出>,

    complted: 完成<IOCP投入完成后得到了响应>

    abort:取消<客户端断开,队列中还没有来得及发送的任务取消>

 

acceptex: 投递了100个,响应了1个

context info: 创建了100个连接上下文(对应的客户端连接)实例, 借出去了100次,还回来1次

sendRequest:创建了1个发送请求<TSendRequest>实例,借出去21次,还回来21次。

 

workers: 3个iocp工作线程(点击[数量]可以看出线程的工作状态<阻塞(忙)/等待(空闲)>)

【DIOCP3-说明书】关于DIOCP3的服务申明

近段时间发现明显关注diocp3的人越来越多,首先感谢大家选择使用DIOCP3,虽然我不能保证diocp3底层100%不出问题,但是我会尽量去保障diocp3底层代码的稳定,使他成为一个稳定的通信库。由于作者现在还是一个苦逼的上班族,还得为老板卖命。为了不至于被老板炒鱿鱼。我今天慎重考虑了下,平常大家在使用diocp3的过程中,碰到bug,请大家点击<<【DIOCP3-说明书】关于DIOCP3服务端常见的问题>> (http://diocp.wedelphi.com/?p=115)看看是否有类似的情况。如果还是搞不定不要担心,没有请剥离一份简单的代码(客户端和服务端)请不要使用三方控件,发可以编译的工程文件给我,我尽量安排时间(一般在中午休息和晚上)调试程序。谢谢大家理解!

【DIOCP3-说明书】关于DIOCP3服务端常见的问题

这几天群里面使用DIOCP3的人越来越多,一般或多或少都会碰到一些问题,碰到问题并不可怕,可怕的是不知道如果下手去查找问题,解决问题。服务端的编写都一样,需要小心谨慎,毕竟我们要写的程序是需要长期运行的,不能有半点马虎。每一行代码都要认真对待,我现在把大家碰到的问题整理下,希望大家碰到问题时,好好检查下代码,看看是不是也有类似的问题。

 

第一,也是很多人容易犯的错误,不要在diocp3事件中,直接访问UI

    这个情况几乎我每次都强调,但基本上90%的人都犯这样的错误,因为diocp3中,所有的事件都在线程中触发的,UI资源一般都不是线程安全的,直接访问UI,一般会锁死线程,程序退出时无法退出进程,而且会出现不可预料的错误。
   日志记录方面如果要显示到Memo中,请使用线程日志安全类SafeLogger,可以参考safelogger的demo,虽然Memo是做的SendMessage处理,还是不建议直接在线程池对Memo直接进行操作

 

第二,访问违规错误。

    首先跟踪下代码看看,访问违规的错误代码是哪一行引起的,看看对象是否提前是否,或者是公用的对象,如果是公用的对象是否有做临界处理。如果异常停留在diocp底层的代码,多数情况下面是程序栈帧被破坏,检查下指针操作的位置(move,copyMemory的位置)看看目标指针是否有越界和指定错误的情况。建议应用层,少用指针和结构体,用操作对象或者内存流来代替结构体和指针操作。

 

第三,日志的问题。

    diocp底层记录日志在Debug模式下面记录日志比较详细,每个连接的断开<包括主动和对方断开>都做了日志记录。那些日志一般都是正常存在的。

 

第四,心跳和重连。

    diocp3中有设置KeepAlive的选项,但是这个选项不是万能的,有很多客户端突然断线,或者某些机器上面会不起作用。这个时候需要做业务层的心跳包,一般处理方法是,客户端定时发送很小的数据包,到服务端,服务端做轮询的超时检测,把超时的连接主动在服务端T掉,客户端在发送数据包的过程中也可以触发没有正常连接的异常,然后进行重连。

 

最后再强调下,服务端编程,要处理要多线程资源访问的问题,注意好指针操作。要写出稳健的服务端,还需要逻辑代码和diocp3的配合,需要谨慎对待。