1、VBA数组底层结构: VBA的数组在底层是SafeArray: 'https://docs.microsoft.com/zh-cn/windows/win32/api/oaidl/ns-oaidl-safearraybound Long ' // 该维的数组存取的下限,一般为0 End Type 'https://docs.microsoft.com/zh-cn/windows/win32/api/oaidl/ns-oaidl-safearray redirectedfrom=MSDN Type SafeArray cDims As Integer ' // 数组的维度 fFeatures As Integer ' 像c语言这样的语言,是有指针的,VBA数组的底层实现应该是使用了一个指针来引用SafeArray结构,而VarPtrArray(Arr)获取到的应该是指针的地址。 2、改变SafeArray的pvDataas地址会有什么情况: 既然知道了数组的内存结构,那我们就尝试把pvDataas改变看看会怎么样: Sub TestArray2() Dim Arr()
DATE QFont IFontDisp* QPixmap IPictureDisp* QVariant VARIANT QVariantList (same as QList<QVariant>) SAFEARRAY (VARIANT) QStringList SAFEARRAY(BSTR) QByteArray SAFEARRAY(BYTE) QRect User defined type QSize User defined (VARIANT) QList<QVariant>& [in, out] SAFEARRAY(VARIANT)* QStringList, const QStringList& [in] SAFEARRAY (BSTR) QStringList& [in, out] SAFEARRAY(BSTR)* QByteArray, const QByteArray& [in] SAFEARRAY(BYTE) QByteArray & [in, out] SAFEARRAY(BYTE)* QObject* [in] IDispatch* QRect& [in, out] struct QRect (user defined) QSize
date; BSTR bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY 图5 0x02 数组 数组存储结构由SAFEARRAY定义: typedef struct tagSAFEARRAY { USHORT cDims; USHORT fFeatures ; 其中各字段含义可参阅[Microsoft Docs——SAFEARRAY]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray 图28 0x06 参阅链接 •[Microsoft Docs——SAFEARRAY structure]https://docs.microsoft.com/en-us/windows/win32/api /oaidl/ns-oaidl-safearray•[Microsoft Docs——VARIANT structure]https://docs.microsoft.com/en-us/windows
实践 /// A thread-safe array. public class SafeArray<Element> { fileprivate let queue = DispatchQueue (label: "Com.BigNerdCoding.SafeArray", attributes: .concurrent) fileprivate var array = [Element] () } // MARK: - Properties public extension SafeArray { var first: Element? (elements) } } } } public extension SafeArray { subscript(index: Int) 接下来,我们可以对传统的非并发安全数组和 SafeArray 进行以下比较: import Foundation import PlaygroundSupport // Thread-unsafe
一维数组与一个多行单列二维数组的数据,在内存中的排列显然是一样的,所以,只要理解数组的底层类型,将一维数组转变为一个多行单列的二维数组就很简单了,只需要改变一下SafeArray就可以,不需要重新复制数据 ,使用完后要修改回去 'retpArray 记录临时开辟的2维数组的地址 Function OneDim2TwoDim(arr As Variant, rows As Long, retsa As SafeArray VBA.IsArray(arr) Then OneDim2TwoDim = -1 Exit Function End If Dim sa As SafeArray 所以不能直接修改一维数组arr,另外引入一个2维数组 Dim tmp() As Variant ReDim tmp(0, 0) As Variant Dim tmpsa As SafeArray 16, VarPtr(tmpsa.rgsabound(0).cElements), 16 OneDim2TwoDim = tmp End Function 这里需要注意的是一维数组的SafeArray
数组在VBA里是一个数据类型,除了这一组顺序索引的元素之外,还有一个记录了数组一些信息的结构体SafeArray。 所以,上面的C1774F8指向的是SafeArray结构体,而并不是数组数据开始的地址: Sub Test() Dim a1() As Byte ReDim a1(1) As Byte p1 = VarPtrArray(a1) Dim p1value As Long CopyMemory VarPtr(p1value), p1, 4 Dim sa As SafeArray 1F5D28F8 1890A4A0 1890A4A0 可以看到sa.pvDataas和VarPtr(a1(0))的地址是同一个地址,这个才是真正的数组数据开始的地方,SafeArray SafeArray记录的数据更多,而且记录的位置也不是在紧挨着数据开始的前面,而是另外开辟空间来记录。 ?
在数据类型Array中,我们知道了数组的底层结构,其中cDims就是指明数组维度的,那么,我们只需要通过修改内存中cDims的值,以及SafeArray中rgsabound记录的元素的个数,那么就可以实现将多维的数组转换为一维数组 SafeArrayBound cElements As Long '// 该维的长度 lLbound As Long ' // 该维的数组存取的下限,一般为0 End Type Private Type SafeArray Then ToOneDim = -1 Exit Function End If Dim ptr As Long Dim sa As SafeArray
SafeArrayBound cElements As Long '// 该维的长度 lLbound As Long ' // 该维的数组存取的下限,一般为0 End Type Private Type SafeArray Then GetArrayDims = 0 Exit Function End If Dim ptr As Long Dim sa As SafeArray
/Excel的sheet集合 CRange currentRange;//当前操作区域 bool isLoad;//是否已经加载了某个sheet数据 COleSafeArray safeArray (ret_ary.vt & VT_ARRAY)) { return; } // safeArray.Clear(); safeArray.Attach(ret_ary); } / { long read_address[2]; VARIANT val; read_address[0] = iRow; read_address[1] = iColumn; safeArray.GetElement { long read_address[2]; VARIANT val; read_address[0] = iRow; read_address[1] = iColumn; safeArray.GetElement { long read_address[2]; VARIANT val; read_address[0] = iRow; read_address[1] = iColumn; safeArray.GetElement
BSTR bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY pbstrVal; IUnknown **ppunkVal; IDispatch **ppdispVal; SAFEARRAY
*/ IDispatch * pdispVal; /* VT_DISPATCH */ SAFEARRAY VT_UNKNOWN */ IDispatch ** ppdispVal; /* VT_BYREF|VT_DISPATCH */ SAFEARRAY
CMFCApplication2Dlg::onComm() { // TODO: 在此处添加消息处理程序代码 VARIANT variant_inp; COleSafeArray safearray_inp ////////以下你可以根据自己的通信协议加入处理代码 variant_inp = m_ctrlComm.get_Input(); //读缓冲区 safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量 len = safearray_inp.GetOneDimSize(); //得到有效数据长度 m_COMIndex) { if (m_COMIndex > 240 * 320 - 1) break; safearray_inp.GetElement
增加这一功能以后,我们可以将标准库直接放到用户库目录下使用(例如网站程序),注意"~\"或"~/"没有区别. 2、新增 com.SafeArray(元素类型,一个或多个数组元素) 函数用于创建COM安全数组
#include <iostream> using namespace std; const int SIZE = 10; class Safearray { private: int arr[SIZE]; public: Safearray() { register int i; for(i = 0; i < SIZE 返回第一个元素 return arr[0]; } return arr[i]; } }; int main() { Safearray
自赋值检测(Self-assignment check) 旧资源释放(Resource cleanup) 新资源分配(New resource allocation) class SafeArray { int* data; size_t size; public: SafeArray& operator=(const SafeArray& other) { other.data, other.data + size, data); return *this; } }; 2.4 异常安全实现 基础实现存在异常安全隐患,改进方案: SafeArray & operator=(const SafeArray& other) { if(this !
args) { //实例化普通的顺序表 List<Integer> array = new ArrayList<>(); //将array转换为线程安全的safeArray List<Integer> safeArray = Collections.synchronizedList(array); } } 因为读写操作都进行了加锁,所以适用于读和写操作频率相对均衡的场景
array SAFEARRAYBOUND rgsaBounds[1]; rgsaBounds[0].cElements = 1; rgsaBounds[0].lLbound = 0; SAFEARRAY
BSTR bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY pbstrVal; IUnknown **ppunkVal; IDispatch **ppdispVal; SAFEARRAY
bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY *pbstrVal; IUnknown **ppunkVal; IDispatch **ppdispVal; SAFEARRAY
0x03 参阅链接 •[Microsoft Docs——SAFEARRAY]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray