不安全代码和指针资料汇编

不安全代码和指针(C# 编程指南)

为了保持类型安全,默认情况下,C# 不支持指针运算。不过,通过使用 unsafe 关键字,可以定义可使用指针的不安全上下文。有关指针的更多信息,请参见主题指针类型。 

注意 

在公共语言运行库 (CLR) 中,不安全代码是指无法验证的代码。C# 中的不安全代码不一定是危险的,只是其安全性无法由 CLR 进行验证的代码。因此,CLR 只对在完全受信任的程序集中的不安全代码执行操作。如果使用不安全代码,由您负责确保您的代码不会引起安全风险或指针错误。有关更多信息,请参见安全性与 C#

不安全代码概述

不安全代码具有下列属性:

· 方法、类型和可被定义为不安全的代码块。

· 在某些情况下,通过移除数组界限检查,不安全代码可提高应用程序的性能。

· 当调用需要指针的本机函数时,需要使用不安全代码。

· 使用不安全代码将引起安全风险和稳定性风险。

· 在 C# 中,为了编译不安全代码,必须用 /unsafe 编译应用程序。

指针类型(C# 编程指南)

在不安全的上下文中,类型可以是指针类型以及值类型或引用类型。指针类型声明具有下列形式之一:

复制

type* identifier;

void* identifier; //allowed but not recommended

下列类型都可以是指针类型:

· sbytebyteshortushortintuintlongulongcharfloatdoubledecimal 或 bool

· 任何枚举类型。

· 任何指针类型。

· 仅包含非托管类型的字段的任何用户定义的结构类型。

指针类型不继承 object,并且指针类型与 object 之间不存在转换。此外,装箱和取消装箱不支持指针。但是,允许在不同指针类型之间以及指针类型与整型之间进行转换。

当在同一个声明中声明多个指针时,仅与基础类型一起使用,而不是作为每个指针名称的前缀。例如:

复制

int* p1, p2, p3;   // Ok

int *p1, *p2, *p3;   // Invalid in C#

指针不能指向引用或包含引用的结构,因为即使有指针指向对象引用,该对象引用也可能会被执行垃圾回收。GC 并不注意是否有任何类型的指针指向对象。

myType* 类型的指针变量的值是 myType 类型的变量的地址。下面是指针类型声明的示例:

示例 

说明 

int* p

是指向整数的指针

int** p

是指向整数的指针的指针

int*[] p

是指向整数的指针的一维数组

char* p

是指向字符的指针

void* p

是指向未知类型的指针

指针间接寻址运算符 可用于访问位于指针变量所指向的位置的内容。例如,对于下面的声明,

复制

int* myVariable;

表达式 *myVariable 表示在 myVariable 中包含的地址处找到的 int 变量。

不能对 void* 类型的指针应用间接寻址运算符。但是,可以使用强制转换将 void 指针转换为其他指针类型,反之亦然。

指针可以为 null。如果将间接寻址运算符应用于 null 指针,则会导致由实现定义的行为。

注意,在方法之间传递指针会导致未定义的行为。示例包括通过 Out 或 Ref 参数向局部变量返回指针或作为函数结果向局部变量返回指针。如果将指针设置在固定的块中,它所指向的变量可能不再是固定的。

下表列出可在不安全的上下文中针对指针执行的运算符和语句:

运算符/语句 

用途 

*

执行指针间接寻址。

->

通过指针访问结构的成员。

[]

对指针建立索引。

&

获取变量的地址。

++ 和 --

递增或递减指针。

加、减

执行指针算法。

==!=<><= 和 >=

比较指针。

stackalloc

在堆栈上分配内存。

fixed 语句

临时固定变量以便可以找到其地址。

固定大小的缓冲区(C# 编程指南)

在 C# 2.0 中,可以使用 fixed 语句在数据结构中创建固定大小的数组。使用现有代码(如:使用其他语言、预先存在的 DLL 或 COM 项目编写的代码)时这种方法非常有用。固定数组可采用允许普通结构成员使用的任何属性或修饰符。唯一的限制是,数组类型必须是 boolbyte char shortintlongsbyteushortuintulongfloat 或 double

复制

private fixed char name[30];

备注 

在以前版本的 C# 中,声明 C++ 样式的固定大小结构是很困难的,因为包含数组的 C# 结构不包含数组元素,而是包含对元素的引用。

C# 2.0 添加了在结构(当用在不安全的代码块中时)中嵌入固定大小的数组的功能。

例如,在 C# 2.0 之前,下面的 struct 的大小为 字节,其中 pathName 数组是对堆分配的数组的引用:

复制

public struct MyArray

{

    public char[] pathName;

    private int reserved;

}

在 C# 2.0 中,struct 可使用嵌入数组进行声明:

复制

public struct MyArray // This code must appear in an unsafe block

{

    public fixed char pathName[128];

}

在此结构中,pathName 数组具有固定的大小和位置,因此可用在其他不安全的代码中。

128 个元素的 char 数组的大小为 256 字节。在固定大小的 char 缓冲区中,每个字符始终占用两个字节,而与编码无关。即使将 char 缓冲区封送到具有 CharSet = CharSet.Auto 或 CharSet = CharSet.Ansi 的 API 方法或结构,也是如此。有关更多信息,请参见 CharSet

另一种常见的固定大小的数组是 bool 数组。bool 数组中的元素的大小始终为一个字节。bool 数组不适合用于创建位数组或位缓冲区。

注意 

除了用 stackalloc 创建的内存,C# 编译器和公共语言运行库 (CLR) 不执行任何安全缓冲区溢出检查。与所有不安全代码一样,请谨慎使用。

不安全缓冲区与常规数组有如下差异:

· 不安全缓冲区只能用在不安全上下文中。

· 不安全缓冲区始终是向量(或一维数组)。

· 数组的声明应包括计数,如 char id[8]。而不能使用 char id[]

· 不安全缓冲区只能是不安全上下文中的结构的实例字段。

如何:使用指针复制字节数组(C# 编程指南)

下面的示例使用指针将字节从一个数组复制到另一个使用指针的数组。

此示例使用 unsafe 关键字,它允许在 Copy 方法内使用指针。fixed 语句用于声明指向源数组和目标数组的指针。这将锁定源数组和目标数组在内存中的位置,使其不会因为垃圾回收操作而移动。这些内存块将在 fixed 块结束时取消锁定。因为本示例中 Copy 函数使用了 unsafe 关键字,它必须使用 /unsafe 编译器选项进行编译。

示例

复制

// compile with: /unsafe

复制

class TestCopy

{

    // The unsafe keyword allows pointers to be used within the following method:

    static unsafe void Copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int count)

    {

        if (src == null || srcIndex < 0 ||

            dst == null || dstIndex < 0 || count < 0)

        {

            throw new System.ArgumentException();

        }

        int srcLen = src.Length;

        int dstLen = dst.Length;

        if (srcLen - srcIndex < count || dstLen - dstIndex < count)

        {

            throw new System.ArgumentException();

        }

        // The following fixed statement pins the location of the src and dst objects

        // in memory so that they will not be moved by garbage collection.

        fixed (byte* pSrc = src, pDst = dst)

        {

            byte* ps = pSrc;

            byte* pd = pDst;

            // Loop over the count in blocks of 4 bytes, copying an integer (4 bytes) at a time:

            for (int i = 0 ; i < count / 4 ; i++)

            {

                *((int*)pd) = *((int*)ps);

                pd += 4;

                ps += 4;

            }

            // Complete the copy by moving any bytes that weren't moved in blocks of 4:

            for (int i = 0; i < count % 4 ; i++)

            {

                *pd = *ps;

                pd++;

                ps++;

            }

        }

    }

    static void Main()

    {

        byte[] a = new byte[100];

        byte[] b = new byte[100];

        for (int i = 0; i < 100; ++i)

        {

            a[i] = (byte)i;

        }

        Copy(a, 0, b, 0, 100);

        System.Console.WriteLine("The first 10 elements are:");

        for (int i = 0; i < 10; ++i) 

        {

            System.Console.Write(b[i] + " ");

        }

        System.Console.WriteLine("\n");

    }

}

输出

The first 10 elements are:

0 1 2 3 4 5 6 7 8 9 

如何:使用 Windows ReadFile 函数(C# 编程指南)

下面的示例通过读取并显示一个文本文件来演示 Windows ReadFile 函数。ReadFile 函数需要使用 unsafe 代码,因为它需要一个作为参数的指针。

传递到 Read 函数的字节数组是托管类型。这意味着公共语言运行库 (CLR) 垃圾回收器可能会随意地对数组使用的内存进行重新定位。为了防止出现这种情况,使用 fixed 来获取指向内存的指针并对它进行标记,以便垃圾回收器不会移动它。在 fixed 块的末尾,内存将自动返回,以便能够通过垃圾回收移动。

此功能称为声明式锁定。锁定的好处是系统开销非常小,除非在 fixed 块中发生垃圾回收(但此情况不太可能发生)。

示例

复制

class FileReader

{

    const uint GENERIC_READ = 0x80000000;

    const uint OPEN_EXISTING = 3;

    System.IntPtr handle;

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]

    static extern unsafe System.IntPtr CreateFile

    (

        string FileName,          // file name

        uint DesiredAccess,       // access mode

        uint ShareMode,           // share mode

        uint SecurityAttributes,  // Security Attributes

        uint CreationDisposition, // how to create

        uint FlagsAndAttributes,  // file attributes

        int hTemplateFile         // handle to template file

    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]

    static extern unsafe bool ReadFile

    (

        System.IntPtr hFile,      // handle to file

        void* pBuffer,            // data buffer

        int NumberOfBytesToRead,  // number of bytes to read

        int* pNumberOfBytesRead,  // number of bytes read

        int Overlapped            // overlapped buffer

    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]

    static extern unsafe bool CloseHandle

    (

        System.IntPtr hObject // handle to object

    );

    public bool Open(string FileName)

    {

        // open the existing file for reading       

        handle = CreateFile

        (

            FileName,

            GENERIC_READ,

            0,

            0,

            OPEN_EXISTING,

            0,

            0

        );

        if (handle != System.IntPtr.Zero)

        {

            return true;

        }

        else

        {

            return false;

        }

    }

    public unsafe int Read(byte[] buffer, int index, int count)

    {

        int n = 0;

        fixed (byte* p = buffer)

        {

            if (!ReadFile(handle, p + index, count, &n, 0))

            {

                return 0;

            }

        }

        return n;

    }

    public bool Close()

    {

        return CloseHandle(handle);

    }

}

class Test

{

    static int Main(string[] args)

    {

        if (args.Length != 1)

        {

            System.Console.WriteLine("Usage : ReadFile <FileName>");

            return 1;

        }

        if (!System.IO.File.Exists(args[0]))

        {

            System.Console.WriteLine("File " + args[0] + " not found.");

            return 1;

        }

        byte[] buffer = new byte[128];

        FileReader fr = new FileReader();

        if (fr.Open(args[0]))

        {

            // Assume that an ASCII file is being read.

            System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();

            int bytesRead;

            do

            {

                bytesRead = fr.Read(buffer, 0, buffer.Length);

                string content = Encoding.GetString(buffer, 0, bytesRead);

                System.Console.Write("{0}", content);

            }

            while (bytesRead > 0);

            fr.Close();

            return 0;

        }

        else

        {

            System.Console.WriteLine("Failed to open requested file");

            return 1;

        }

    }

}

unsafeC# 参考)

unsafe 关键字表示不安全上下文,该上下文是任何涉及指针的操作所必需的。有关更多信息,请参见不安全代码和指针(C# 编程指南)

可以在类型或成员的声明中使用 unsafe 修饰符。因此,类型或成员的整个正文范围均被视为不安全上下文。例如,以下是用 unsafe 修饰符声明的方法:

复制

unsafe static void FastCopy(byte[] src, byte[] dst, int count)

{

    // Unsafe context: can use pointers here.

}

不安全上下文的范围从参数列表扩展到方法的结尾,因此指针在以下参数列表中也可以使用:

复制

unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}

还可以使用不安全块从而能够使用该块内的不安全代码。例如:

复制

unsafe

{

    // Unsafe context: can use pointers here.

}

若要编译不安全代码,必须指定 /unsafe 编译器选项。无法通过公共语言运行库验证不安全代码。 

示例 

复制

// cs_unsafe_keyword.cs

// compile with: /unsafe

using System;

class UnsafeTest

{

   // Unsafe method: takes pointer to int:

   unsafe static void SquarePtrParam(int* p)

   {

      *p *= *p;

   }

   unsafe static void Main()

   {

      int i = 5;

      // Unsafe method: uses address-of operator (&):

      SquarePtrParam(&i);

      Console.WriteLine(i);

   }

}

输出

25

fixed 语句(C# 参考)

fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。Fixed 还可用于创建固定大小的缓冲区

备注 

fixed 语句设置指向托管变量的指针并在 statement 执行期间钉住该变量。如果没有 fixed 语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知地重定位变量。C# 编译器只允许在 fixed 语句中分配指向托管变量的指针。

复制

// assume class Point { public int x, y; }

// pt is a managed variable, subject to garbage collection.

Point pt = new Point();

// Using fixed allows the address of pt members to be

// taken, and "pins" pt so it isn't relocated.

fixed ( int* p = &pt.x )

{

    *p = 1; 

}

可以用数组或字符串的地址初始化指针:

复制

fixed (int* p = arr) ...  // equivalent to p = &arr[0]

fixed (char* p = str) ... // equivalent to p = &str[0]

只要指针的类型相同,就可以初始化多个指针:

复制

fixed (byte* ps = srcarray, pd = dstarray) {...}

要初始化不同类型的指针,只需嵌套 fixed 语句:

复制

fixed (int* p1 = &p.x)

{

    fixed (double* p2 = &array[5])

    {

        // Do something with p1 and p2.

    }

}

执行完语句中的代码后,任何固定变量都被解除固定并受垃圾回收的制约。因此,不要指向 fixed 语句之外的那些变量。

在不安全模式中,可以在堆栈上分配内存。堆栈不受垃圾回收的制约,因此不需要被锁定。有关更多信息,请参见 stackalloc

示例 

复制

// statements_fixed.cs

// compile with: /unsafe

using System;

class Point

    public int x, y; 

}

class FixedTest 

{

    // Unsafe method: takes a pointer to an int.

    unsafe static void SquarePtrParam (int* p) 

    {

        *p *= *p;

    }

    unsafe static void Main() 

    {

        Point pt = new Point();

        pt.x = 5;

        pt.y = 6;

        // Pin pt in place:

        fixed (int* p = &pt.x) 

        {

            SquarePtrParam (p);

        }

        // pt now unpinned

        Console.WriteLine ("{0} {1}", pt.x, pt.y);

    }

}

输出

25 6

stackallocC# 参考)

在不安全的代码上下文中使用,可以在堆栈上分配内存块。 

复制

int* fib = stackalloc int[100];

备注 

上面的示例在堆栈而不是堆上分配了一个内存块,它的大小足以包含 100 个 int 类型的元素;该块的地址存储在 fib 指针中。此内存不受垃圾回收的制约,因此不必将其钉住(通过 fixed)。内存块的生存期受定义它的方法的生存期的限制(没有在方法返回之前释放内存的途径)。

stackalloc 仅在局部变量的初始值设定项中有效。

由于涉及指针类型,stackalloc 要求不安全上下文。请参见不安全代码和指针

stackalloc 类似于 运行时库中的 _alloca

安全性 

不安全代码是天生比非不安全替代代码安全性更低的代码。但是,通过使用 stackalloc 可以自动启用公共语言运行库 (CLR) 中的缓冲区溢出检测功能。如果检测到缓冲区溢出,进程将尽快终止,以最大限度地减小执行恶意代码的机会。

示例 

复制

// cs_keyword_stackalloc.cs

// compile with: /unsafe

using System;

class Test

{

    static unsafe void Main()

    {

        int* fib = stackalloc int[100];

        int* p = fib;

        *p++ = *p++ = 1;

        for (int i = 2; i < 100; ++i, ++p)

        {

            *p = p[-1] + p[-2];

        }

        for (int i = 0; i < 10; ++i)

        {

            Console.WriteLine(fib[i]);

        }

    }

}

输出

1

1

2

3

5

8

13

21

34

55

转载于:https://www.cnblogs.com/jxnclyk/archive/2010/05/28/1746132.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg-从flv文件中提取AAC音频数据保存为文件

AAC ADTS格式协议&#xff1a; 从flv文件中提取AAC音频数据保存为文件。 如果需要详细了解AAC ADTS格式&#xff0c;可以查询文档。 原文件&#xff1a; 提取aac文件&#xff1a; main.c #include <stdio.h> #include <libavutil/log.h>> #include <lib…

N Queen(代码、分析、汇编)

目录&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;代码&#xff1a; main.c #include <stdio.h>/* 程序描述&#xff1a;输出N*N中符合左右对角线与上下左右方向都没被使用的位置在每一行的所有情况使用检测左上角&#xff0c;正上角&#xff0c;右上…

Python-身份证核对

中华人民共和国居民身份证号码由17 位数字和1位校验码组成。其中&#xff0c;前6位为所在地编号&#xff0c;第7~14 位为出生年月日&#xff0c;第15~17位为登记流水号&#xff0c;其中第17位偶数为女性&#xff0c;奇数为男性。校验码的生成规则如下: 将前面的身份证号码17位数…

树存储结构(代码、分析、汇编)

目录&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;代码&#xff1a; LinkList.h LinkList.c 线性表 GTree.h #ifndef _GTREE_H_ #define _GTREE_H_typedef void GTree;//定义树类型 typedef void GTreeData;//定义节点中存放数据的类型 typedef void (GTre…

二元矩阵峰值搜索_好斗的牛(二元搜索)

二元矩阵峰值搜索A farmer has built a long barn with N stalls. The stalls are placed in a straight manner at positions from x1, x2, ...xN. But his cows (C) are aggressive and don’t want to be near other cows. To prevent cows from hurting each other, he wan…

Python---冒泡排序、选择排序

冒泡排序 依次输入n个数&#xff0c;进行冒泡排序 冒泡排序法&#xff0c;即两个相邻的进行比较&#xff0c;比较之后换位置 def bubbleSort(arr):n len(arr)for i in range(n):for j in range(0, n-i-1):if arr[j] > arr[j1] :arr[j], arr[j1] arr[j1], arr[j]arr[] n…

react js 添加样式_如何在React JS Application中添加图像?

react js 添加样式Hello! In this article, we will learn how to add images in React JS? I remember when I just started coding in React JS, I thought adding images would be done exactly as it is in HTML. I later realized that it was different. 你好&#xff0…

二叉树(多路平衡搜索树)-(代码、分析、汇编)

目录&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;代码&#xff1a; BTree.h #ifndef _BTREE_H_ #define _BTREE_H_#define BT_LEFT 0 //定义左子节点标识 #define BT_RIGHT 1 //定义右子节点标识typedef void BTree;//定义树类型 typedef unsigned long lo…

Python---二分法查找

输入n个数&#xff0c;通过二分法查找该数的下标 def binarySearch(arr,value):m 0#开始n len(arr#最后)while m<n:mid(mn)//2#计算中间位置if valuearr[mid]:#查找成功&#xff0c;返回元素对应的位置return midelif value>arr[mid]:#在后面一半元素中继续查找mmid1e…

SQL捕获异常

原文地址 http://technet.microsoft.com/zh-cn/office/ms179296%28vsql.100%29在 Transact-SQL 中使用 TRY...CATCHTransact-SQL 代码中的错误可使用 TRY…CATCH 构造处理&#xff0c;此功能类似于 Microsoft Visual C 和 Microsoft Visual C# 语言的异常处理功能。TRY…CATCH …

二叉树遍历(代码,分析,汇编)

目录&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;代码&#xff1a; BTree.h BTree.c 二叉树&#xff08;多路平衡搜索树&#xff09; LinkQueue.h #ifndef _LINKQUEUE_H_ #define _LINKQUEUE_H_typedef void LinkQueue;//定义队列类型LinkQueue* LinkQueu…

Python---查找序列的最长递增子序列

查找序列的最长递增子序列 什么是序列的最长递增子序列&#xff1f; 答&#xff1a;在一个数值序列中&#xff0c;找到一个子序列&#xff0c;使得这个子序列元素的数值依次递增&#xff0c;并且这个子序列的长度尽可能地大。这就是所谓的最长递增子序列 from itertools impo…

ffmpeg-从mp4、flv、ts文件中提取264视频流数据

ffmpeg-从mp4、flv、ts文件中提取264视频流数据 main.c #include <stdio.h> #include <libavutil/log.h> #include <libavformat/avio.h> #include <libavformat/avformat.h>void proc(int need_to_annexb, char* in_file, char* out_file) {AVForma…

线索化二叉树(代码 、分析 、汇编)

目录&#xff1a;代码&#xff1a;分析&#xff1a;汇编&#xff1a;代码&#xff1a; BTree.h BTree.c 二叉树&#xff08;多路平衡搜索树&#xff09; SeqList.h SeqList.c 顺序表 main.c #include <stdio.h> #include <stdlib.h> #include "BTree.h&qu…

Python---寻找给定序列中相差最小的两个数字

编写函数&#xff0c;寻找给定序列中相差最小的两个数字 def getTwoClosestElements(arr):#先进行排序&#xff0c;使得相邻元素最接近#相差最小的元素必然相邻seq sorted(arr)#先进行排序dif float(inf)#无穷大#遍历所有元素&#xff0c;两两比较&#xff0c;比较相邻元素的…

Python---利用蒙特.卡罗方法计算圆周率近似值

利用蒙特.卡罗方法计算圆周率近似值 什么是蒙特.卡罗方法&#xff1f; 答&#xff1a;蒙特卡罗方法是一种计算方法。原理是通过大量随机样本&#xff0c;去了解一个系统&#xff0c;进而得到所要计算的值。 正方形内部有一个相切的圆&#xff0c;它们的面积之比是π/4。 这里假…

FLV封装格式的分析

FLV封装格式的分析&#xff0c;各种详细的参数比较多没有详细解释&#xff0c;这是总体的格式分布。详细的参数说明可以参照文档。 以flv格式内封装的音频流是aac、视频流是h264分析&#xff1a; flv文件tag部分截图&#xff1a;可以看到音频TAG、视频TAG是交错存储的

《计算机基础复习》===数据库技术基础

数据库系统三级结构&#xff1a; 数据库系统一般划分为三个抽象级&#xff1a;用户级、概念级、物理级。 1&#xff09;用户级数据库&#xff1a;对应于外模式。它是用户看到和使用的数据库&#xff0c;又称用户视图&#xff1b;用户级数据库主要由外部记录组成&#xff0c;不同…

bs架构 erp 进销存_从依赖经验到用柔性ERP,企业少走了多少弯路?

企业在面对紧急订单时&#xff0c;传统企业将面临两难问题&#xff1a;如不接受紧急订单,可能会导致潜在的顾客丢失,损失市场占有率;接受紧急订单,可能会给企业带来很多管理上的问题,如材料采购、库存管理等。而企业通过信息化手段提升生产计划与控制的柔性&#xff0c;则可从容…

云端: 小软件大平台,绿色又安全 V0.9 Beta3(090722)

云端 是一个小软件&#xff0c;但又是一个大平台。安装云端之后&#xff0c;再使用其他软件不再需要安装——一点、下载、直接使用&#xff1b;并且&#xff0c;通过虚拟化的运行环境&#xff0c;能够保持系统长久的干净、绿色&#xff0c;并保持软件与系统的安全隔离——此方面…