在这个帖子的11楼:http://topic.csdn.net/u/20081223/18/9E5CEC7B-5025-460A-BA30-2BC85704BEB8.htmlunsigned说:所有指针都一律定义为Long,但是自己要记得,或者做个标记,需要用到的时候,再通过VarPtr等传入指针(实体一定不能被释放掉)。
eglic问:那对于结构里面,固定长度的字符串呢?这个没办法用指针了吧?
unsigned说:使用byte array,对于unicode应该可以使用[string * N],当然也可以使用两倍的Byte Array或者Integer Array然后Copy进去,实际上对于结构最关键的就是结构对齐。在这篇文章的后部:http://www.vbgood.com/vb.good/article-do-view-articleid-2386.html
作者写道:有一点需要特别注意,在VB中指针的算法非常重要。此外,你必须计算元素的大小,因为VB不会帮你完成这项工作。你还必须处理缺乏无符号长整型数据类型的问题。下面的函数实现了无符号算法
Function UnsingedAdd (ByVal Start As Long, ByVal Incr As Long) As Long
Const SignBit As Long = &H80000000
UnsignedAdd=(Start Xor SignBit) + Incr Xor SignBit
End Function没看懂的是标记为红色的部分,貌似他们在说相同的东西:
(1)unsigned说:“对于结构最关键的就是结构对齐”。这是什么意思?
(2)第二篇文章说:“在VB中指针的算法非常重要”。这个指针的算法是什么?能举个例子说明么?一般什么时候用?
(3)第二篇文章说:“你必须计算元素的大小”。这又是什么意思
(4)能逐字逐句解释一下上面这个“无符号算法”的意思么?
eglic问:那对于结构里面,固定长度的字符串呢?这个没办法用指针了吧?
unsigned说:使用byte array,对于unicode应该可以使用[string * N],当然也可以使用两倍的Byte Array或者Integer Array然后Copy进去,实际上对于结构最关键的就是结构对齐。在这篇文章的后部:http://www.vbgood.com/vb.good/article-do-view-articleid-2386.html
作者写道:有一点需要特别注意,在VB中指针的算法非常重要。此外,你必须计算元素的大小,因为VB不会帮你完成这项工作。你还必须处理缺乏无符号长整型数据类型的问题。下面的函数实现了无符号算法
Function UnsingedAdd (ByVal Start As Long, ByVal Incr As Long) As Long
Const SignBit As Long = &H80000000
UnsignedAdd=(Start Xor SignBit) + Incr Xor SignBit
End Function没看懂的是标记为红色的部分,貌似他们在说相同的东西:
(1)unsigned说:“对于结构最关键的就是结构对齐”。这是什么意思?
(2)第二篇文章说:“在VB中指针的算法非常重要”。这个指针的算法是什么?能举个例子说明么?一般什么时候用?
(3)第二篇文章说:“你必须计算元素的大小”。这又是什么意思
(4)能逐字逐句解释一下上面这个“无符号算法”的意思么?
解决方案 »
- grid++report4.5 vb 参数化查询sql
- 服务器上的一个SQLSERVER数据库,想在本地机上保存属于本地机的数据备份,当心服务器出问题时的数据丢失。如何不写代码直接备份,即在给服务器存记录时也同时给本地机存一份,不写同样的代码或少量写代码能实现吗?
- 怎么提取文本里的内容发送到串口上?
- 退出程序时,关闭FTP总是死机
- 求助:请问有没有自动生成印章的好办法啊,谢谢
- 求教打开VBA时,其它XML文件的使用问题
- 哪个高手会用wpe啊?
- 关于存储过程
- 各位大虾,谁知道在VB中怎样切断网络连接,谢谢
- 求ADO 连接远程SQL的使用方法,关键是格式/参数,要详解啊,谢谢先.
- 在Vb.net 里怎么让主板发出声音。
- ASP.NET(VB)添加数据问题?
说笑的,“高字节对齐”,每个变量会占用4字节的空间,且是“字边界对齐”:
Private Sub Command1_Click()
Dim t As Boolean, strTest$, bB As Byte, iLong&, iT%, iKK&
strTest = "123456"
Debug.Print Hex$(VarPtr(t))
Debug.Print Hex$(VarPtr(strTest)), Hex$(StrPtr(strTest))
Debug.Print Hex$(VarPtr(bB))
Debug.Print Hex$(VarPtr(iLong))
Debug.Print Hex$(VarPtr(iT))
Debug.Print Hex$(VarPtr(iKK))
strTest = strTest & "ABCD"
Debug.Print Hex$(VarPtr(strTest)), Hex$(StrPtr(strTest))
End Sub
输出:
12F442 (t 的地址,分配12F440~12F443,使用12F442~12F443)
12F43C 190484 (strTest 的地址,分配12F43C~12F43F,全用。字符串内容存放190484起的地方)
12F43A (bB 的地址,分配12F438~12F43B,使用12F43A)
12F434 (iLong 的地址,分配12F434~12F437,全使用)
12F432 (iT 的地址,分配12F430~12F434,使用12F432~12F434)
12F42C (iKK 的地址,分配12F42C~12F42F,全使用)
12F43C 1900FC (strTest实际内容的地址发生了变化,可见变长字符串运算是要重新分配内存的)
当然数组元素的存放应该是连续的,只是首址按双字对齐。(2)VB中本身不支持“指针变量”,因此相应的运算就要你自己处理。你要清楚你所面对的数据类型占用的空间大小。
比如 C/C++ 中,指针p++:如果p所指类型是 int、long、flat及各种类型的指针时,它的地址会移动四字节;而如果它所指类型是char,则只会移动一字节。(3)在VB中,用 Type 定义数据类型后,用它声明的变量,你就得仔细分析一下它每个变量会占用多少空间了。并且有时候跟你所想的完全不一样!而在 C/C++ 中,你几乎用不着操心这个问题。
type t1
b as byte
end type len(t1) = 1 VC:
struct t1{
char a;
}; sizeof(t1) == 4
明白了没?结构对齐就是这个意思。因为VC会把结构按 4 或 8 字节对齐 VB不会,如果你不注意这个问题,把VB的结构直接传递到API中会导致出错。
(2)第二篇文章说:“在VB中指针的算法非常重要”。这个指针的算法是什么?能举个例子说明么?一般什么时候用? 在VC中,你取得一个数组的某一元素的指针,
如 int a[888];
int *p = & a[0]; 你可以通过用 p+5 得到 a[5] 的地址, 但是在VB中,这样做是达不到目的的。 在VB中想通过一个数组元素的地址算出另一元素的地址就是“这个指针的算法”,初学者不建议玩这个。
Private Type Strc
a as Byte
b as Integer
c as Long
d as Byte
End Type
按理说,访问成员d,从结构首地址算起,应该偏移7个字节。然而这是错的!!
因为VB会按32位对齐分配结构,a--1Byte,b--2Bytes,还差1Byte,留空(当然不能把c截断啦),所以c安排到了首地址开始偏移32位的位置。后面依此类推。这样,访问成员d,需要偏移8字节。
还有,涉及到结构中包含数组时,也要遵循这个原则。(2)VB没有C语言的指针类型,从而带来的问题是,在VB中,对你声明的长整形指针变量自加自减只是机械地加了“1”而已,并没有像C编译器那样,会根据指针指向的数据类型自动地加减这个数据类型的字节数。
比如:
int a[2] = {99, 88};
int *p = a;
p++;
a的每个元素是两个字节,p自加后,指向a[1]。因此,如果是在VB里,想指向a(1),需要这样:
Dim a(1) As Integer
a(0) = 99
a(1) = 88
Dim p As Long
p = VarPtr(a(0))
p = p + 2
其实就是问题(3)里的“你必须计算元素的大小”。(3)参照(2)(4)因为VB把Long型全部看作带符号的,因此范围是[-80000000, 7FFFFFFF]。
整个函数的意思就是,把Start看作无符号数进行自加自减操作(注意Incr可正可负),返回值也看作无符号数(虽然用Debug等输出时带符号,就是说有时会显示为负数,但不影响应用)。
typedef struct _tagMyStruct{
unsigned char x;
unsigned char y;
int z;
}MyStruct;
看上去只有 sizeof(unsigned char) + sizeof(unsigned char) + sizeof(int) = 1 + 1 + 4,但是在Win32平台下,在没有强制做存储压缩的情况下,编译器却实际上让它占用了8字节的空间。x和y各占一个字节,所以x和y被分到同一个机器字长的空间当中,由于z是int,刚好是一个机器字长,为了访问z的时候能够一次性读入cache,而不是先从第一个机器字长的空间当中读取半个z,然后再读取第二个机器字长的空间才读取到后半个z,编译器就把z直接放到了下一个机器字长的空间当中,从而就导致了y和z中间隐藏了2个字节的空间。在VB当中,由是以压缩存储的,也就是说
type MyStruct
x as byte
y as byte
z as long
End Type
这样一个结构,在VB当中就是6个字节,从而如果你在调用一个API的时候,刚好碰到上面的C结构,那么你就很有可能会把一个在C当中占了8字节的结构定义成了只有6个字节,如此你在调用API的时候,就会导致内存访问溢出,后果是非常严重。正确地做法应该是:
1).在定义结构的时候注意字节对齐,尽可能对定义的结构当中的“空洞”进行填充,例如定义成:
typedef struct _tagMyStruct{
unsigned char x;
unsigned char y;
short reserved;
int z;
}MyStruct;
养成良好的习惯;
2).在与第三方进行接口对接的时候,很难加以强制别人进行遵守,所以应该在使用时尽量分析清楚,或者了解清楚,从而定义出一个完全匹配的结构
type MyStruct
x as byte
y as byte
reserved as integer
z as long
End Type2.没有什么“指针算法”这一说法,如果没有理解错,原意应该是对指针偏移进行正确计算。指针只是一个形象的说法,实际在内存当中就是一个地址,对于VB语言本身地址操作是比较弱的,但是可以借助于API,以及VarPtr,StrPtr,以及address of等等操作符做到。在如C/C++等当中,当定义好一个结构指针类型之后,进行指移偏移运算的时候,会以结构大小进行偏移移位:
typedef struct _tagMyStruct{
unsigned char x;
unsigned char y;
short reserved;
int z;
}MyStruct,*LPMyStruct;LPMyStruct P;
P = 0;
P ++;//这里是P = (LPMyStruct)((unsigned long)P + sizeof(MyStruct)),而不是P = (LPMyStruct)((unsigned long)P + 1);而在VB当中则完全需要自己进行计算。个人理解这里所指的“指针算法”应该是一个相对性的计算方式。3.参照14.最高位为符号位,当通过xor把符合位去掉时就可以把一个无符号大数缩小,然后就可以进行运算,最后再把符合位替换回去,就相当于,先减2147483648,然后进行计算,最的再加回去。这里需要满足的是两个条件:
1).结果不能溢出;
2).start为大于2147483648的一个无符号数
3).Incr是一个较小的正数
对于地址对齐的问题,这根本就不用考虑了>在VB中指针的算法非常重要。此外,你必须计算元素的大小
这个说法好像不成立,要么就是我没理解他的意思那个小函数...
把两个有符号的数格式为无符号的数然后相加,但返回的结果还是被格式化为long,以至于结果不正确
不知道意义在哪...
VC:
struct t1{
char a;
}; sizeof(t1) == 1
具体是这样的:
UnsingedAdd = (Start Xor SignBit) + Incr Xor SignBit
先反转Start的符号位(即最高位)(欺骗VB,省得溢出),然后和Incr相加,结果的符号位再反转。
讨论(以VB的带符号的补码运算机制):
A)若Start>0,Incr>0或Start<0,Incr<0
反转后相加时一正一负,不会溢出
B)若Start>0,Incr<0
反转后相加时,只要Start绝对值大于Incr绝对值,就不会溢出。也正符合指针没有负地址的要求。
这也正是这个函数的妙处。从而也说明了Incr可以是负数!
C)或Start<0,Incr>0
反转后相加时,同样只要Start绝对值大于Incr绝对值,就不会溢出。
在实际应用中,Start<0的情况不会出现。
Const SignBit As Long = &H80000000
UnsignedAdd=(Start Xor SignBit) + Incr Xor SignBit
End Function
这个明明只异或了一次啊?
Dim t As Boolean, strTest$, bB As Byte, iLong&, iT%, iKK&
strTest = "123456"
Debug.Print "Hex$(VarPtr(t)) : " & Hex$(VarPtr(t)) & " : boolean 2字节"
Debug.Print "Hex$(VarPtr(strTest)) : " & Hex$(VarPtr(strTest)), "Hex$(StrPtr(strTest)) : " & Hex$(StrPtr(strTest)) & " : 10字节加字符串长度"
Debug.Print "Hex$(VarPtr(bB)) : " & Hex$(VarPtr(bB)) & " : 1字节"
Debug.Print "Hex$(VarPtr(iLong)) : " & Hex$(VarPtr(iLong)) & " : 4字节"
Debug.Print "Hex$(VarPtr(iT)) : " & Hex$(VarPtr(iT)) & " : integer 2字节"
Debug.Print "Hex$(VarPtr(iKK)) : " & Hex$(VarPtr(iKK)) & " : 4字节"
strTest = strTest & "ABCD"
Debug.Print "Hex$(VarPtr(strTest)) : " & Hex$(VarPtr(strTest)), "Hex$(StrPtr(strTest)) : " & Hex$(StrPtr(strTest)) & " : 10字节加字符串长度"
End Sub输出:Hex$(VarPtr(t)) : 13F772 : boolean 2字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : CBA0B24 : 10字节加字符串长度
Hex$(VarPtr(bB)) : 13F76A : 1字节
Hex$(VarPtr(iLong)) : 13F764 : 4字节
Hex$(VarPtr(iT)) : 13F762 : integer 2字节
Hex$(VarPtr(iKK)) : 13F75C : 4字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : DD41924 : 10字节加字符串长度
xor的效果就是当相同时取反,如果x的符合位为1则取反,即被替换成0,就相当于减去了&H80000000,如果不为1,则保持原来的值不变.
那“最后再把符合位替换回去”,这个是如何做到的呢?只替换xor了一次,没看到替换回去啊?
Dim t As Boolean, strTest$, bB As Byte, iLong&, iT%, iKK&
strTest = "123456"
Debug.Print "Hex$(VarPtr(t)) : " & Hex$(VarPtr(t)) & " : boolean 2字节"
Debug.Print "Hex$(VarPtr(strTest)) : " & Hex$(VarPtr(strTest)), "Hex$(StrPtr(strTest)) : " & Hex$(StrPtr(strTest)) & " string: 10字节加字符串长度"
Debug.Print "Hex$(VarPtr(bB)) : " & Hex$(VarPtr(bB)) & " byte: 1字节"
Debug.Print "Hex$(VarPtr(iLong)) : " & Hex$(VarPtr(iLong)) & " long: 4字节"
Debug.Print "Hex$(VarPtr(iT)) : " & Hex$(VarPtr(iT)) & " integer: 2字节"
Debug.Print "Hex$(VarPtr(iKK)) : " & Hex$(VarPtr(iKK)) & " long: 4字节"
strTest = strTest & "ABCD"
Debug.Print "Hex$(VarPtr(strTest)) : " & Hex$(VarPtr(strTest)), "Hex$(StrPtr(strTest)) : " & Hex$(StrPtr(strTest)) & " : 10字节加字符串长度"
End Sub输出:
Hex$(VarPtr(t)) : 13F772 : boolean 2字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : C8C1C24 string: 10字节加字符串长度
Hex$(VarPtr(bB)) : 13F76A byte: 1字节
Hex$(VarPtr(iLong)) : 13F764 long: 4字节
Hex$(VarPtr(iT)) : 13F762 integer: 2字节
Hex$(VarPtr(iKK)) : 13F75C long: 4字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : E35A20C : 10字节加字符串长度
我是在 VB IDE环境下运行输出的。
输出的地址不同是正常现象,这肯定跟具体环境有关。
只是你看一下:相邻变量的地址差值,在不同的环境下也是相同的,说明对变量分配的字节空间是确定的,且分配规则相同。
红色的那个地址是跟系统资源有关系的,即使在同一台机器上,不同的时候运行,它也会有变化的。
============================================================================
12F442 (t 的地址,分配12F440~12F443,使用12F442~12F443)
12F43C 190484 (strTest 的地址,分配12F43C~12F43F,全用。)
12F43A (bB 的地址,分配12F438~12F43B,使用12F43A)
12F434 (iLong 的地址,分配12F434~12F437,全使用)
12F432 (iT 的地址,分配12F430~12F434,使用12F432~12F434)
12F42C (iKK 的地址,分配12F42C~12F42F,全使用)
12F43C 1900FC (变长字符串运算是要重新分配内存的)
-----------------------------------------------------------------------------
Hex$(VarPtr(t)) : 13F772 : boolean 2字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : CBA0B24 : 10字节加字符串长度
Hex$(VarPtr(bB)) : 13F76A : 1字节
Hex$(VarPtr(iLong)) : 13F764 : 4字节
Hex$(VarPtr(iT)) : 13F762 : integer 2字节
Hex$(VarPtr(iKK)) : 13F75C : 4字节
Hex$(VarPtr(strTest)) : 13F76C Hex$(StrPtr(strTest)) : DD41924 : 10字节加字符串长度
对于占用不到4字节的变量,多余的空间都是空出不用的。
它选择在第三个字节上,可能在运算、分离数据上实现起来方便些吧。
x1=x xor y
x = x1 xor y抱歉是我的理解错误,下面的代码测试一下就明白了
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)Private Type MyStruct
X As Byte
y As Byte
m As Integer
z As Long
End Type
Private Sub Form_Load()
Dim X As MyStruct
Dim l As Long, m As Long
l = 8888888
X.X = 1
X.y = 2
X.z = 9999999
'以非对齐结构取z的值到l
m = VarPtr(X.X) + 2
CopyMemory ByVal VarPtr(l), ByVal m, 4
MsgBox l
'以对齐结构取z的值取l
m = VarPtr(X.X) + 4
CopyMemory ByVal VarPtr(l), ByVal m, 4
MsgBox l
End Sub
Const SignBit As Long = &H80000000
UnsignedAdd = (Start Xor SignBit) + Incr Xor SignBit '这里明明只xor了一次啊?哪里做了“再把符合位替换回去”的操作?
End Function
==以下是你在4楼的发言==
4.最高位为符号位,当通过xor把符合位去掉时就可以把一个无符号大数缩小,然后就可以进行运算,最后再把符合位替换回去,就相当于,先减2147483648,然后进行计算,最的再加回去。这里需要满足的是两个条件:
1).结果不能溢出;
2).start为大于2147483648的一个无符号数
3).Incr是一个较小的正数
typedef struct _tagA{
char x;
}A;
typedef struct _tagB{
A a;
char y;
}B;
typedef struct _tagC{
B b;
int z;
}C;
typedef struct _tagD{
C c;
char t;
}D;printf("sizeof(A)=%d,sizeof(B)=%d,sizeof(C)=%d,sizeof(D)=%d\r\n",sizeof(A),sizeof(B),sizeof(C),sizeof(D));
那么,如果像soyokaze在8楼说的那样,我用这个函数做指针的运算的话,还是不够用的吧?因为结果并不是真正的指针的值,是吧?
x as byte
y as byte
z as long
End Type
这说明在VB里结构没有按字长对齐啊?
“结果是有符号的”,的确,VB对于32位Long数据都按照有符号数运算,这个反映在:
1)运算结果小于-&H80000000和大于&H7FFFFFFF会溢出;
2)MSB为1的,用Debug等会显示为负数。
不过,这只是VB的编译器这么认为,其实一个32位数作为地址指针时,就是无符号的,因为这个地址需要传给API呀,C++库呀什么的,直接传过去,OK的。
所以,这个函数只是借助VB的语法、规则和编译器完成了对一个32位数的加减法,并不在乎VB怎么解释这个数,只要保证结果正确即可。
再多说一下,符号只是人们为了运算简便而认为规定的,在硬件实现上,不论有无符号的两个数,MCU都同样放到全加器里进行加法运算,结果一样(指1、0的组合)的,只是解释不同,就代表两个不同的数。
LenB(MyStruct) = 8VB的Len()和LenB()是有微妙的区别的。
Len()返回表面上(怎么说好呢,就是VB包装过的吧)的长度,LenB()返回实际占的字节数还有一例:
Dim s as string
s = "hello"
Debug.Print Len(s), LenB(s)结果为:
5 10
x as byte
y as byte
z as long
End Type更有说服力。这时候得到的结果也是一个溢出,一个是9999999说明,虽然结构变量占用的字节数用len去取是6字节,但是它的数据在存放的时候是按字长对齐的。
to Soyokaze, 你在3楼写的:还有,涉及到结构中包含数组时,也要遵循这个原则。这个这个是和上面这句话是一个意思么?另外,想请Soyokaze帮看看2楼的回复(1),是否那种情况实际上不会出现?因为VB其实是按字长对齐的。
x As Byte
y As Byte
z As Long
End TypePrivate Sub Form_Load()
Dim t As MyStruct
With t
.x = 12
.y = 34
.z = &H5678 '在内存中存放为 &H78 &H56 &H00 &H00
End With
Dim p As Long
Dim b As Byte
p = VarPtr(t)
Call CopyMemory(b, ByVal p + 2, 1)
Debug.Print Hex(b)
Call CopyMemory(b, ByVal p + 4, 1)
Debug.Print Hex(b)
End Sub结果是:
0
78
“strTest实际内容的地址发生了变化,可见变长字符串运算是要重新分配内存的”
这个的确这样,我遇到过。不光是变长字符串,包括用 Redim 声明的变长数组(包括非字串类型),重新Redim时,各元素地址也会发生变化。所以呀,VB的效率~~
抱歉,我我我还是不理解。无限地羞愧……主要是对16进制加减法不太熟悉、对内存结构也不大了解……Function UnsingedAdd (ByVal Start As Long, ByVal Incr As Long) As Long
Const SignBit As Long = &H80000000
UnsignedAdd=(Start Xor SignBit) + Incr Xor SignBit
End Function比如,假设start=H8FFFFFFE,incr=1,那么我希望的指针位置实际上是H8FFFFFFF
用这个函数计算完得到的指针位置传到API里难道正确么?我怎么觉得算出来的是FFFFFFF,跟我想要的结果差的远啊?
1 Xor 80000000 = 80000001
FFFFFFE + 80000001 = 8FFFFFFF
(Start Xor SignBit) ------> &H8FFFFFFE Xor &H80000000 = &H0FFFFFFE
(Start Xor SignBit)+1 ----> &H0FFFFFFE + 1 = &H0FFFFFFF
(Start Xor SignBit)+1 Xor SignBit ---> &H0FFFFFFF Xor &H80000000 = &H8FFFFFFF
谢谢Chen and WangMu.这么说,“UnsignedAdd=(Start Xor SignBit) + Incr Xor SignBit ” 这一行等价于UnsignedAdd=((Start Xor SignBit) + Incr )Xor SignBit 也就是说,“xor”这个运算符的优先级是低于“+”的?
Private Function UnsignedAdd(ByVal lX As Long, ByVal lY As Long) As Long
Dim lX4 As Long
Dim lY4 As Long
Dim lX8 As Long
Dim lY8 As Long
Dim lResult As Long lX8 = lX And &H80000000
lY8 = lY And &H80000000
lX4 = lX And &H40000000
lY4 = lY And &H40000000 lResult = (lX And &H3FFFFFFF) + (lY And &H3FFFFFFF) If lX4 And lY4 Then
lResult = lResult Xor &H80000000 Xor lX8 Xor lY8
ElseIf lX4 Or lY4 Then
If lResult And &H40000000 Then
lResult = lResult Xor &HC0000000 Xor lX8 Xor lY8
Else
lResult = lResult Xor &H40000000 Xor lX8 Xor lY8
End If
Else
lResult = lResult Xor lX8 Xor lY8
End If UnsignedAdd = lResult
End Function
个人愚见,若无十分必要,尽量不要在vb中折腾这些东西,用c、c++好了,直接了当。
楼很高
如果是连续的内存,比如你说的结构数组,他的对齐是整体对齐,而不是分布式
也就是说如果有 dim i() as type(2个字节结构) ,这种情况下并非所有元素都处于对齐位置上
但也包含一个很特殊的情况,起始地址不为对齐地址上,但这种情况基本不会发生的,除非你特意安排了这样一个东西,否则系统那里申请过来的,是基本不会有这种的
有点说乱了,总之就是,连续的内存,他的对齐是整体对齐,而不是象你说的每个元素都要对齐
那么,如果是结构数组,就每个数组元素都是32位对齐的吧?
=============
是的。不必格外填充字节,就自然地对齐了。
b)现在的主流操作系统是 32 位的,它们用 4 字节对齐。1)变量的声明,用栈空间,编译器(VB)决定,所以 2 字节对齐。
2)结构的成员,无论用什么空间,其内部划分编译器(VB)决定,所以 2 字节对齐。
3)而动态内存的使用,通过操作系统在堆上分配空间,就用 4 字节对齐。
所以看字符串的地址、动态数组的首个成员的地址(SAFEARRAY.pvData),16进制地址的末尾不是0就是8。
2)结构的成员,无论用什么空间,其内部划分编译器(VB)决定。
3)而动态内存的使用,通过操作系统在堆上分配空间,由OS决定。
我对LZ的这个问题,这么理解一下哈:
60L所说的是有数据后的地址对齐,如果地址不对齐的话,当要再使用此变量中的数据时,就会取不出正确的来
而LZ的意思只是说明了,在IDE中定义一个变量后,IDE或者OS如何来分配内存地址这个变量,二者说的不是同
一东西.当你定义好一个变量,系统将按照一定的规定分配内存地址给这个变量,可能LZ不大好理解,我们举个例子来说
明一下:
Private Type DemoType
strString As String
byteByte() As Byte
End TypePrivate Sub Form_Load()
Dim Demo As DemoType
Dim i As Integer
ReDim byteByte(100)
For i = 0 To 100
byteByte(i) = "" '这里赋字节类数据
Next i
Demo.strString = "This is string"
End Sub那么所谓的地址对齐,就是指的上面的这个自定义类型DemoType
在它里面有二个变量,分别是字符型和字节型,那么在给这个自定义类型赋完值后,在异机上面需要
取得这个自定义类型中的数据,就必须注意对齐地址
ReDim Demo.byteByte(100)
For i = 0 To 100
Demo.byteByte(i) = "" '这里赋字节类数据
Next i
注意上面的Start <0只是站在VB的角度上,作为地址,Start一直是一个无符号数。
start = &H7fffffff
incr = 1
直接加会溢出,调用函数得&H80000000例2
start = &H80000000
incr = -1
直接加会溢出,调用函数得&H7fffffff例3
start = 3
incr = -4 (&Hfffffffc)
调用函数溢出例4
start = &Hfffffffc (即带符号数-4)
incr = 5
调用函数溢出
incr可以是负数(代表指针自减),输入时可以采用诸如5、-6等形式。但要明确,对于负数,是以其补码存储到计算机里的(同时MSB为1)。例如-6,其实就是&HFFFFFFFA。
然后这两个16进数相加,按位全加。取其后面的32位作为结果。
什么情况会溢出呢?两个符号相反的数相加不会溢出,对于两个符号相同的数,如果结果的bit31(即MSB)与bit32(进位位,不体现在结果中,硬件完成)相反(即一个是1,一个是0),溢出。
所以,分析这个函数时,需要按我上面所说的把start与incr转换为16进制,这样函数具体怎样工作的,一目了然。
既然做无符号运算,有 UnsignedAdd 就要有对应的 UnsignedSub。
你的帖子那里分析什么补码是完全错误的。
我们的目标用 UnsingedAdd() 进行无符号数的加法,其值域范围就是 UInt32 : &H00000000 - &HFFFFFFFF (0 - 4294967295)。
而 VB 的 Long 是 Int32: &H80000000 - &H7FFFFFFF ((-2147483648) - 2147483647),可以用与 Unsigned 运算的只有 &H00000000 - &H7FFFFFFF (0 - 2147483647)。那么其最高位 &H80000000 (2147483648) 就不能参与用 VB.Long 的加法运算,必须自己处理,这就是 54 楼函数中要提取 lX8、lY8 的原因。
而且次高位 &H40000000 (1073741824) 的相加会向最高位产生进位,在 VB.Long 的加法运算中就是溢出错误,必须自己处理,这就是 54 楼函数中要提取 lX4、lY4 的原因。
至于剩余的位(54 楼函数中对 lX或lY 进行 And &H3FFFFFFF 操着后)进行相加,最多进位到次高位 &H40000000,完全可以用 VB.Long 进行加法运算。而所谓的自己处理,就是用 Xor 来模拟不进位的二进制加法防止溢出错误,其实就是在已知某个位的值时,通过 Xor 强制反转该位的值(0/1反转)。'注:以下注释中的加减运算都是无符号运算'
Private Function UnsignedAdd(ByVal lX As Long, ByVal lY As Long) As Long
Dim lX4 As Long
Dim lY4 As Long
Dim lX8 As Long
Dim lY8 As Long
Dim lResult As Long '提取最高位'
lX8 = lX And &H80000000
lY8 = lY And &H80000000
'提起次高位'
lX4 = lX And &H40000000
lY4 = lY And &H40000000
'剩余位直接相加'
lResult = (lX And &H3FFFFFFF) + (lY And &H3FFFFFFF) If lX4 And lY4 Then '次高位同时为 1,和为 &H80000000'
'lResult = lResult + 次高位和&H80000000 + X的最高位 + Y的最高位'
'其中向更高位 &H100000000 的进位直接忽略了'
lResult = lResult Xor &H80000000 Xor lX8 Xor lY8
ElseIf lX4 Or lY4 Then '次高位只有一个 1'
'lResult = lResult + 次高位和&H40000000 + X的最高位 + Y的最高位'
If lResult And &H40000000 Then '剩余位的和向次高位有进位'
' lResult + 次高位和&H40000000'
'= lResult + &H80000000 - &H40000000'
'= lResult Xor &HC0000000
lResult = lResult Xor &HC0000000 Xor lX8 Xor lY8
Else
lResult = lResult Xor &H40000000 Xor lX8 Xor lY8
End If
Else '次高位全0,和为0'
'lResult = lResult + 次高位和&H00000000 + X的最高位 + Y的最高位'
lResult = lResult Xor lX8 Xor lY8
End If UnsignedAdd = lResult
End Function
既然做无符号运算,有 UnsignedAdd 就要有对应的 UnsignedSub。
(1)是不是有这种定论:对两个无符号整数按位异或,就等价于,这个两个无符号整数相加?
(2)如果这个结论成立,这个结论是否可推及有符号整数的十六进制运算?