C#调用C++ memcpy实现各种参数类型的内存拷贝 VS marshal.copy的实现 效率对比

时间:2022-12-17 12:12:32
using System;
using System.Runtime.InteropServices;
using System.IO;
namespace tx
{
struct ST
{
public char c1;
public int x;
public int y;
}
class Ct
{
[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern void MemCopy(byte[] dest, byte[] src, int count);//字节数组到字节数组的拷贝 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern void MemCopy(int[] dest, byte[] src, int count);//字节数组到整形数组的拷贝 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public unsafe static extern void MemCopy(ref ST dest, byte[] src, int count);//注意只有结构体能这么做,class不可以 static void Main(string[] args)
{
//测试----------------------------------------------
var ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter(ms);
writer.Write((byte)'a');
writer.Write((byte)'b');
writer.Write((byte)'c');
writer.Write((byte)'d');
writer.Write((Int32));
writer.Write((Int32));
var len = ms.Length;
int[] bs = new int[len/];
byte[] bss = new byte[len]; byte[] buf = ms.GetBuffer();
var ot = new ST();
MemCopy(bs, buf, (int)len);
MemCopy(bss, buf, (int)len);
MemCopy(ref ot, buf, (int)len);//注意只有结构体能这么做,class不可以
} } }

Marshal对应的实现ByteToStruct,及效率对比完整程序如下:以读取魔兽世界M2文件为例,经测试发现ByteToStruct用时为MemCopy的3倍到4倍

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using NUnit.Framework.Internal.Filters;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics; using Debug = UnityEngine.Debug;
using System.Threading;
using System.ComponentModel; struct Sphere
{
/*0x00*/public float xmin, ymin, zmin;
/*0x0C*/public float xmax, ymax, zmax;
/*0x18*/public float radius;
}; struct ModelHeader {
public byte id0, id1, id2, id3;
public byte ver0, ver1, ver2, ver3;
public UInt32 nameLength;
public UInt32 nameOfs;
public UInt32 GlobalModelFlags; // 1: tilt x, 2: tilt y, 4:, 8: add another field in header, 16: ; (no other flags as of 3.1.1); public UInt32 nGlobalSequences; // AnimationRelated
public UInt32 ofsGlobalSequences; // A list of timestamps.
public UInt32 nAnimations; // AnimationRelated
public UInt32 ofsAnimations; // Information about the animations in the model.
public UInt32 nAnimationLookup; // AnimationRelated
public UInt32 ofsAnimationLookup; // Mapping of global IDs to the entries in the Animation sequences block.
//UInt32 nD;
//UInt32 ofsD;
public UInt32 nBones; // BonesAndLookups
public UInt32 ofsBones; // Information about the bones in this model.
public UInt32 nKeyBoneLookup; // BonesAndLookups
public UInt32 ofsKeyBoneLookup; // Lookup table for key skeletal bones. public UInt32 nVertices; // GeometryAndRendering
public UInt32 ofsVertices; // Vertices of the model.
public UInt32 nViews; // GeometryAndRendering
//UInt32 ofsViews; // Views (LOD) are now in .skins. public UInt32 nColors; // ColorsAndTransparency
public UInt32 ofsColors; // Color definitions. public UInt32 nTextures; // TextureAndTheifAnimation
public UInt32 ofsTextures; // Textures of this model. public UInt32 nTransparency; // H, ColorsAndTransparency
public UInt32 ofsTransparency; // Transparency of textures.
//UInt32 nI; // always unused ?
//UInt32 ofsI;
public UInt32 nTexAnims; // J, TextureAndTheifAnimation
public UInt32 ofsTexAnims;
public UInt32 nTexReplace; // TextureAndTheifAnimation
public UInt32 ofsTexReplace; // Replaceable Textures. public UInt32 nTexFlags; // Render Flags
public UInt32 ofsTexFlags; // Blending modes / render flags.
public UInt32 nBoneLookup; // BonesAndLookups
public UInt32 ofsBoneLookup; // A bone lookup table. public UInt32 nTexLookup; // TextureAndTheifAnimation
public UInt32 ofsTexLookup; // The same for textures. public UInt32 nTexUnitLookup; // L, TextureAndTheifAnimation, seems gone after Cataclysm
public UInt32 ofsTexUnitLookup; // And texture units. Somewhere they have to be too.
public UInt32 nTransparencyLookup; // M, ColorsAndTransparency
public UInt32 ofsTransparencyLookup; // Everything needs its lookup. Here are the transparencies.
public UInt32 nTexAnimLookup; // TextureAndTheifAnimation
public UInt32 ofsTexAnimLookup; // Wait. Do we have animated Textures? Wasn't ofsTexAnims deleted? oO public Sphere collisionSphere;
public Sphere boundSphere; public UInt32 nBoundingTriangles; // Miscellaneous
public UInt32 ofsBoundingTriangles;
public UInt32 nBoundingVertices; // Miscellaneous
public UInt32 ofsBoundingVertices;
public UInt32 nBoundingNormals; // Miscellaneous
public UInt32 ofsBoundingNormals; public UInt32 nAttachments; // O, Miscellaneous
public UInt32 ofsAttachments; // Attachments are for weapons etc.
public UInt32 nAttachLookup; // P, Miscellaneous
public UInt32 ofsAttachLookup; // Of course with a lookup.
public UInt32 nEvents; //
public UInt32 ofsEvents; // Used for playing sounds when dying and a lot else.
public UInt32 nLights; // R
public UInt32 ofsLights; // Lights are mainly used in loginscreens but in wands and some doodads too.
public UInt32 nCameras; // S, Miscellaneous
public UInt32 ofsCameras; // The cameras are present in most models for having a model in the Character-Tab.
public UInt32 nCameraLookup; // Miscellaneous
public UInt32 ofsCameraLookup; // And lookup-time again, unit16
public UInt32 nRibbonEmitters; // U, Effects
public UInt32 ofsRibbonEmitters; // Things swirling around. See the CoT-entrance for light-trails.
public UInt32 nParticleEmitters; // V, Effects
public UInt32 ofsParticleEmitters; // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles.
public UInt32 nUnknown; // Apparently added in models with the 8-flag only. If that flag is not set, this field does not exist!
public UInt32 ofsUnknown; // An array of shorts, related to renderflags.
}; public class m2 : MonoBehaviour { [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern void MemCopy(byte[] dest, byte[] src, int count);//字节数组到字节数组的拷贝 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern void MemCopy(int[] dest, byte[] src, int count);//字节数组到整形数组的拷贝 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
static extern void MemCopy(ref ModelHeader dest, byte[] src, int count);//注意只有结构体能这么做,class不可以 // Use this for initialization
void Start () {
LoadMesh ("Assets/models/creature/arcticcondor.m2");
} // Update is called once per frame
void Update () { } #region public
public UInt32[] globalSequences; #endregion #region private
void LoadMesh(string filePath){
if(false == File.Exists(filePath)){
Debug.LogError ("file not exist : " + filePath);
return;
} var bytes = File.ReadAllBytes (filePath); var buffer = new BufferedStream (new MemoryStream (bytes)); var wt = new Stopwatch ();
wt.Start (); var theader = new ModelHeader ();
var size_header = Marshal.SizeOf (theader);
MemCopy (ref theader, bytes, size_header); Debug.Log ("MemCopy------------------------" + wt.Elapsed);
wt.Stop (); var wt2 = new Stopwatch ();
wt2.Start ();
var header = (ModelHeader)ByteToStruct (bytes, typeof(ModelHeader)); Debug.Log ("ByteToStruct------------------------" + wt2.Elapsed);
wt2.Stop (); if(header.id0 != 'M' || header.id1 != 'D' || header.id2 != '' || header.id3 != '' ){
Debug.LogError ("read m2 header : invalid id0, id1, id2, id3");
return;
} if(header.nameOfs != && header.nameOfs != ){
Debug.LogError ("Invalid model nameOfs=" + header.nameOfs);
return;
} // Error check
// 10 1 0 0 = WoW 5.0 models (as of 15464)
// 10 1 0 0 = WoW 4.0.0.12319 models
// 9 1 0 0 = WoW 4.0 models
// 8 1 0 0 = WoW 3.0 models
// 4 1 0 0 = WoW 2.0 models
// 0 1 0 0 = WoW 1.0 models if(bytes.Length < header.ofsParticleEmitters){
Debug.LogError ("unable to load the model \"" + filePath);
return;
} if(header.nGlobalSequences > ){
globalSequences = new UInt32[header.nGlobalSequences]; } } void RenderMesh(){ } public static object ByteToStruct(byte[] bytes, Type type)
{
int size = Marshal.SizeOf(type);
if (size > bytes.Length)
{
return null;
}
//分配结构体内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将byte数组拷贝到分配好的内存空间
Marshal.Copy(bytes, , structPtr, size);
//将内存空间转换为目标结构体
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
return obj;
} #endregion }