我使用扩展方法将float数组转换为字节数组:
public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
int arrayLength = floatArray.Length > count ? count : floatArray.Length;
byte[] byteArray = new byte[4 * arrayLength];
fixed (float* floatPointer = floatArray)
{
fixed (byte* bytePointer = byteArray)
{
float* read = floatPointer;
float* write = (float*)bytePointer;
for (int i = 0; i < arrayLength; i++)
{
*write++ = *read++;
}
}
}
return byteArray;
}
Run Code Online (Sandbox Code Playgroud)
我知道数组是指向与元素类型和数量信息相关的内存的指针.此外,在我看来,如果没有像上面那样复制数据,就没有办法从字节数组转换到字节数组.
我明白了吗?甚至不可能编写IL来从指针,类型和长度创建数组而不复制数据?
编辑:谢谢你的答案,我学到了一些基础知识,并尝试了新的技巧!
在最初接受Davy Landman的回答之后,我发现虽然他出色的StructLayout hack确实将字节数组转换为浮点数组,但它却无法正常工作.展示:
[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
[FieldOffset(0)]
public …Run Code Online (Sandbox Code Playgroud) 我有一个大字典,其中键是十进制的,但System.Decimal的GetHashCode()非常糟糕.为了证明我的猜测,我运行了一个带有100.000 neigboring小数的for循环并检查了分布.100.000个不同的十进制数仅使用2个(两个!!!)不同的哈希码.
十进制表示为16个字节.就像Guid一样!但是Guid的GetHashCode()发行版非常好.如何在C#中将小数转换为Guid尽可能便宜? 不安全的代码没问题!
编辑:请求测试,所以这里是代码:
decimal d = 96000000000000000000m;
Dictionary<int, int> hashcount = new Dictionary<int, int>();
int length = 100000;
for (int i = 0; i < length; i++)
{
int hashcode = d.GetHashCode();
int n;
if (hashcount.TryGetValue(hashcode, out n))
{
hashcount[hashcode] = n + 1;
}
else
{
hashcount.Add(hashcode, 1);
}
d++;
}
Console.WriteLine(hashcount.Count);
Run Code Online (Sandbox Code Playgroud)
这打印7.我不记得给我2的起始小数.
我正在贡献的一个应用程序启动用C编写的组件.
C进程做了一些相当重的运算,如果你不小心可以真正锤击你的CPU.
有没有办法为.NET生成的外部进程设置限制?
我已经看到这个artivcle在操作系统级别设置硬内存限制,CPU有类似的东西吗?
有没有人试图将Java对象移出堆?我尝试使用不安全的库来使用序列化,反序列化和存储字节数组.但是复杂的对象中包含多个对象,这使得这个过程非常繁琐.更好的解决方案?
我正在尝试使用不安全的库将uint32转换为Go中的字节数组(4个字节):
h := (uint32)(((fh.year*100+fh.month)*100+fh.day)*100 + fh.h)
a := make([]byte, unsafe.Sizeof(h))
copy(a, *(*[]byte)(unsafe.Pointer(&h)))
Run Code Online (Sandbox Code Playgroud)
前两行是正确的,但后来我在复制调用时遇到运行时错误(意外故障地址).
下一步是调用Write
_, err = fi.Write(a)
Run Code Online (Sandbox Code Playgroud)
将4个字节写入文件.
我发现了类似主题的其他问题,但没有一个有工作代码.我也知道不安全是不安全的.
任何帮助将不胜感激.
我发现我的应用程序花了25%的时间在循环中执行此操作:
private static int Diff (int c0, int c1)
{
unsafe {
byte* pc0 = (byte*) &c0;
byte* pc1 = (byte*) &c1;
int d0 = pc0[0] - pc1[0];
int d1 = pc0[1] - pc1[1];
int d2 = pc0[2] - pc1[2];
int d3 = pc0[3] - pc1[3];
d0 *= d0;
d1 *= d1;
d2 *= d2;
d3 *= d3;
return d0 + d1 + d2 + d3;
}
}
Run Code Online (Sandbox Code Playgroud)
如何提高此方法的性能?我的想法到目前为止:
编辑:为方便起见,一些反映真实环境和用例的测试代码.(实际上,涉及的数据更多,并且数据不会在单个大块中进行比较,而是在每个kb的许多块中进行比较.)
public static class ByteCompare …Run Code Online (Sandbox Code Playgroud) 我今天使用Class Library (Package)Visual Studio 2015中的新模板创建了一个类库.显然,它使用了一种奇特的新项目格式ASP.NET xproj来构建软件包.虽然我没关系,但如何从库中调用不安全的代码?我查看了Project> Properties> Build,其中可以选择切换不安全的代码,但我得到的只是:
所以是的,没有这样的运气.我甚至尝试"<AllowUnsafeBlocks>true</AllowUnsafeBlocks>"手动粘贴到.xproj文件中,但编译器仍然抱怨.
是否可以在不为不安全方法创建另一个非xproj程序集的情况下启用此功能?
我试图定义一个属性,返回指向泛型类型参数的指针,如下所示:
public class MemWrapper<T> where T: struct
{
readonly IntPtr pointerToUnmanagedHeapMem;
// ... do some memory management also ...
public unsafe T* Ptr
{
get {return (T*)(pointerToUnmanagedHeapMem);}
}
}
Run Code Online (Sandbox Code Playgroud)
编译器抱怨无法声明指向托管类型T的指针或获取其地址或大小(CS0208).奇怪的是,如果我用一个具体的结构手动替换泛型类型参数,那就是
public class MyStructMemWrapper
{
readonly IntPtr pointerToUnmanagedHeapMem;
// ... do some memory management also ...
public unsafe MyStruct* Ptr
{
get {return (MyStruct*)(pointerToUnmanagedHeapMem);}
}
}
Run Code Online (Sandbox Code Playgroud)
一切都很好.但是,我必须为我使用的每个结构创建一个特殊版本的包装器.那么为什么通用甚至关心它正在铸造什么样的不安全指针呢?
背景信息:我使用的是本机dll,它反过来调用我的c#回调函数,并将其作为指针传递给我最常用的用户数据结构(更准确地说:伪装成IntPtr).为了能够传递GC稳定指针,我在非托管堆上分配我的用户数据结构.因此,我必须注意最后再次释放内存.
由于这是当然都在一个什么样的忠实C#程序员可以承受的极限,我创建一个包装类(周围堆分配和指针的使用情况,以结构)分开我尽可能多地从丑陋的东西.为了尽可能方便地为非托管堆上的结构赋值,我想定义上面的属性.
public struct MyStruct {public double x;}
// ...
MemWrapper<MyStruct> m = new MemWrapper<MyStruct>();
unsafe
{
// ideally I would like to …Run Code Online (Sandbox Code Playgroud) &mut T并&mut T导致编译错误;太好了,两次可变地借款是客观上的错误。
是*mut T和*mut T未定义的行为,还是这是完全正确的事情?也就是说,可变指针别名有效吗?
是什么使事情变得更糟的是,&mut T和*mut T实际上编译和作品如预期,我可以通过引用,指针,然后再参考修改值...但我看到有人说,这是不确定的行为。是的,“有人说过”是我唯一的信息。
这是我测试的内容:
fn main() {
let mut value: u8 = 42;
let r: &mut u8 = &mut value;
let p: *mut u8 = r as *mut _;
*r += 1;
unsafe { *p += 1; }
*r -= 1;
unsafe { *p -= 1; }
println!("{}", value);
}
Run Code Online (Sandbox Code Playgroud)
当然,主要的问题是:
注意 —感谢trentcl 指出此示例在创建时实际上会导致复制p2。可以通过用u8非Copy类型替换来确认。然后,编译器抱怨此举。可悲的是,这并不能使我更接近答案,仅是提醒我,仅由于Rust的move语义,我就可以得到意想不到的行为而不会成为未定义的行为。
fn main() { …Run Code Online (Sandbox Code Playgroud) 现在提交Microsoft Connect ; 如果您觉得需要修理请立即投票.我也简化了测试用例:
byte* data = (byte*) 0x76543210;
uint offset = 0x80000000;
byte* wrong = data + offset;
byte* correct = data + (uint) 0x80000000;
// "wrong" is now 0xFFFFFFFFF6543210 (!)
// "correct" is 0xF6543210
Run Code Online (Sandbox Code Playgroud)
看看IL,就我所知,C#编译器做的一切都正确,错误在于JITter.
原始问题:这里发生了什么?
byte* data = (byte*)Marshal.AllocHGlobal(0x100);
uint uioffset = 0xFFFF0000;
byte* uiptr1 = data + uioffset;
byte* uiptr2 = data + (uint)0xFFFF0000;
ulong uloffset = 0xFFFF0000;
byte* ulptr1 = data + uloffset;
byte* ulptr2 = data + (ulong)0xFFFF0000;
Action<string, ulong> dumpValue = …Run Code Online (Sandbox Code Playgroud)