socket.sendbuf(@p,len); 出错,p是包含动态数组域的record,why???(300分)

  • 主题发起人 主题发起人 shangshang
  • 开始时间 开始时间
S

shangshang

Unregistered / Unconfirmed
GUEST, unregistred user!
用socket发送缓冲区。
send函数。 想直接发送一个record P;
p中有一个域是array of char.
发送前 setlength过了。
跟踪时p中各个域的值一切正常。 但捕获发送的字节发现全成了乱码。
why?? 难道record中的各个域在内存中不是连续的? 还是如果有动态数组域的话,就不是连续的。不能用send(@p,len_p)?? 那要怎么发呢??
请高手指点。 谢谢?
 
record
在内存中不一定连续,双字节对齐(详间内存对齐篇)
原因;cpu一个时钟周期读取一个字(双字节),速度快
packed record
才是内存连续的,但碰到但字节要多读取一次
解决办法:
1、packed record
2、按字节读取
3、流处理

方法多多...
 
楼上说的根本就[:(]

动态数组的本质是指针,所以动态数组的内容你要单独发送
 
补编译指令:
{$A8} 默认为 8 字节对齐(上面说错了,不好意思)
{$A4} 代表 4 字节对齐
{$A2}, {$A1} 类似
不过cpu读取是双字节一个周期:)
 
to tseug:
谢谢指正!
确实,动态数组是个原因,楼主发过去包含一段指针过去(没取到动态数组的实际地址)
但我认为也存在record的问题
它毕竟不是紧缩存储的
希望继续指正
 
我已经packed record了。

本以为发送过程内声明一个p就可以了,不必再另开缓冲区以一次发送整个包体。看着代码也好看。 呵呵。
这样看来,还非得再声明一个发送缓冲区? 那岂不是不用声明p了,直接往缓冲区顺序填下去,然后sendbuf了事?
噢,tseug, 我这样考虑可以吗?
另外,如果不是变长的,是不是肯定就是连续的,肯定可以直接用@p发送了呢?
希望大侠继续指点一下。

uiit,谢谢你的帮助,不过你没指到点儿上。呵呵。再次谢谢。
 
to 楼主:
不好意思,没指到点上
(问题看的匆忙,只看到你的内存连续和record字眼了[:)]以后改)
直接添缓冲,看起来笨,却很保险。
可以用内存拷贝。弄到一个buffer,再发。

另:如果是动态数组,不管变长不变长,它的声明是指针,它是在声明时就分配了的
如果你这时候用@p将会出错,它只是指针变量的存储地址
只有在setlength(p,lenth)时才会分配一段连续内存,才会把内存段的首址设给p
这是后的@p可以发,但要注意长度!

呵呵,这次应该看准了:)
 
其实@p是指向record的指针地址。根本不该用的。
虽然setlength(p,lenth)时才会分配一段连续内存(p是record,不能用setlength,可以声明个Precord,然后new足够的内存。) ,但p中的动态数组域,比如a:array of char. 却是用另一个setlength设置的连续地址,这个地址开头却未必是a在p 中的地址。也不可能是。
不知道我说的对不对。呵呵。有点小晕。

我还有三个非技术帖子,没人回答,却也删除不了,分放在那里可惜了。uiit你去看看吧。
其他大侠有看到的,我也会给。谢谢
 
如果你跟踪一下就知道了,那个动态数组的域实际上只保存了一个4字节指针,当你
Send(@P,SizeOf(P))的时候,发送过去的动态数组域也是一个指针,虽然你接收到
的数值和发送的是一样的,但是作为指针却未必指向以一个有效的区域,指针是与
当前环境相关的,类似的还有String,Variant等类型,所以你如果要发送包含有类似
类型的记录时,要逐个域发送他的长度和内容
 
你也可以看看这个
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3330773
 
谢谢,
其实我考虑过。我send的时候不时用的Send(@P,SizeOf(P)) 而是算出实际总共要发送的大小len 。用send(@p,len)的。 呵呵。关键就是,这个len里其实不包含动态数组中填的内容。是吧。呵呵
 
晕死
我的p值得是动态数组不是你的record
弄清动态数组的内存分配你就可以随便操作了
这样说吧
var
dArr: Array of integer; // 开辟4个字节,存储指针

begin

label1.Caption := IntTohex(Integer(@dArr), 4); // 存储指针的地址

label2.Caption := IntToHex(Integer(dArr), 4); // 指针默认初始化nil

SetLength(dArr, 5); // 分配内存段

label3.Caption := IntToHex(Integer(@dArr), 4); // 存储指针地址未变

label4.Caption := IntToHex(Integer(dArr), 4); // 指针值指向分配的内存首址

label5.Caption := IntToHex(Integer(@dArr[0]), 4);// 分配内存首址(和4一样)

end;
说这么多,只为坚持自己正确(也许表达不好,不好意思)
居然要我去非技术区捡分......没时间
 
uiit:
你误会我了。呵呵,可能是我说话太随意了。
其实代码我都能写出,也知道大概是怎么回事,想跟诸位确认一下。
感谢你做的测试程序,使我更明朗。

至于检分之说,是您太见外了。点我的名字就可以看到我的三个问题了。那三个问题
是04年的,一直放着,您去了。我想一是感谢你些分数。二是你是帮我的忙结束问题啊。
我没别的意思,请千万别往小处想。呵呵。
 
嘿,楼主,玩笑而已!
俺也是对自己感兴趣的问题弄明白点而已
哈哈,俺已这么大年纪怎么会想分数
如果是RMB可能会哈(条件〉几百块)
 
后退
顶部