纯API函数实现串口读写。

以最后决定用纯API函数实现串口读写。
先从网上搜索相关代码(关键字:C# API 串口),发现网上相关的资料大约来源于一个版本,那就是所谓的msdn提供的样例代码(msdn的具体出处,我没有考证),其它的代码大都是它的变种。
其实这个示例代码是有问题的,也就是说DCB结构体声明的有问题,虽然该代码可以正常通信,不过如果你设置了奇偶校验的话,你会发现奇偶校验无效。
VC中的DCB结构声明如下:
typedef struct _DCB {
    DWORD DCBlength;      /* sizeof(DCB)                     */
    DWORD BaudRate;       /* Baudrate at which running       */
    DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */
    DWORD fParity: 1;     /* Enable parity checking          */
    DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */
    DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */
    DWORD fDtrControl:2; /* DTR Flow control                */
    DWORD fDsrSensitivity:1; /* DSR Sensitivity              */
    DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
    DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */
    DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */
    DWORD fErrorChar: 1; /* Enable Err Replacement          */
    DWORD fNull: 1;       /* Enable Null stripping           */
    DWORD fRtsControl:2; /* Rts Flow control                */
    DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
    DWORD fDummy2:17;     /* Reserved                        */
    WORD wReserved;       /* Not currently used              */
    WORD XonLim;          /* Transmit X-ON threshold         */
    WORD XoffLim;         /* Transmit X-OFF threshold        */
    BYTE ByteSize;        /* Number of bits/byte, 4-8        */
    BYTE Parity;          /* 0-4=None,Odd,Even,Mark,Space    */
    BYTE StopBits;        /* 0,1,2 = 1, 1.5, 2               */
    char XonChar;         /* Tx and Rx X-ON character        */
    char XoffChar;        /* Tx and Rx X-OFF character       */
    char ErrorChar;       /* Error replacement char          */
    char EofChar;         /* End of Input character          */
    char EvtChar;         /* Received Event character        */
    WORD wReserved1;      /* Fill for now.                   */
} DCB, *LPDCB;
 
有问题的代码DCB结构声明如下:
[StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            public int DCBlength;
            public int BaudRate;
            public int fBinary;
            public int fParity;
            public int fOutxCtsFlow;
            public int fOutxDsrFlow;
            public int fDtrControl;
            public int fDsrSensitivity;
            public int fTXContinueOnXoff;
            public int fOutX;
            public int fInX;
            public int fErrorChar;
            public int fNull;
            public int fRtsControl;
            public int fAbortOnError;
            public int fDummy2;
            public uint flags;
            public ushort wReserved;
            public ushort XonLim;
            public ushort XoffLim;
            public byte ByteSize;
            public byte Parity;
            public byte StopBits;
            public byte XonChar;
            public byte XoffChar;
            public byte ErrorChar;
            public byte EofChar;
            public byte EvtChar;
            public ushort wReserved1;
        }
对C++比较熟悉网友应该知道,结构体中这种格式的声明,如DWORD fBinary: 1;是以位为单位进行变量设置的,DCB中相关位一共占4个字节,也就是相当于C#中的一个int变量所占的空间。很明显上面的DCB结构会有问题,实际上后面你设置的串口参数,如奇偶校验由于偏移有问题,虽然你设置了,其实都没有设置成功。
其实也不是我说人家的DCB声明错了就错了,在SerialPort类中你就可以找到微软官方自己的DCB声明(需要反编译SerialPort类),声明如下:
[StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            public int DCBlength;
            public int BaudRate;
            public uint Flags;
            public ushort wReserved;
            public ushort XonLim;
            public ushort XoffLim;
            public byte ByteSize;
            public byte Parity;
            public byte StopBits;
            public byte XonChar;
            public byte XoffChar;
            public byte ErrorChar;
            public byte EofChar;
            public byte EvtChar;
            public ushort wReserved1;
        }
并且专门有一个设置位标志的函数,如下:
internal void SetDcbFlag(int whichFlag, int setting)
        {
            uint num;
            setting = setting << whichFlag;
            if ((whichFlag == 4) || (whichFlag == 12))
            {
                num = 3;
            }
            else if (whichFlag == 15)
            {
                num = 0x1ffff;
            }
            else
            {
                num = 1;
            }
            dcb.flags &= ~(num << whichFlag);
            dcb.flags |= (uint)setting;
        }
经过修改能正确运行的API代码如下(注意,由于我是在WinCE平台上运行,所以DLL的路径为" //windows//coredll.dll",你修改为"kernel32"后即可在PC机使用):
///<summary>
    /// API串口类 叶帆修改 http://blog.csdn.net/yefanqiu
    ///</summary>
    public class CommPort
    {
        ///<summary>
        ///端口名称(COM1,COM2...COM4...)
        ///</summary>
        public string Port = "COM1:";
        ///<summary>
        ///波特率9600
        ///</summary>
        public int BaudRate = 9600;
        ///<summary>
        ///数据位4-8
        ///</summary>
        public byte ByteSize = 8; //4-8
        ///<summary>
        ///奇偶校验0-4=no,odd,even,mark,space
        ///</summary>
        public byte Parity = 0;   //0-4=no,odd,even,mark,space
        ///<summary>
        ///停止位
        ///</summary>
        public byte StopBits = 0;   //0,1,2 = 1, 1.5, 2
        ///<summary>
        ///超时长
        ///</summary>
        public int ReadTimeout = 200;
        ///<summary>
        ///串口是否已经打开
        ///</summary>
        public bool Opened = false;
        ///<summary>
        /// COM口句柄
        ///</summary>
        private int hComm = -1;
 
        #region "API相关定义"
        private const string DLLPATH = " //windows//coredll.dll"; // "kernel32";
 
        ///<summary>
        /// WINAPI常量,写标志
        ///</summary>
        private const uint GENERIC_READ = 0x80000000;
        ///<summary>
        /// WINAPI常量,读标志
        ///</summary>
        private const uint GENERIC_WRITE = 0x40000000;
        ///<summary>
        /// WINAPI常量,打开已存在
        ///</summary>
        private const int OPEN_EXISTING = 3;
        ///<summary>
        /// WINAPI常量,无效句柄
        ///</summary>
        private const int INVALID_HANDLE_VALUE = -1;
 
        private const int PURGE_RXABORT = 0x2;
        private const int PURGE_RXCLEAR = 0x8;
        private const int PURGE_TXABORT = 0x1;
        private const int PURGE_TXCLEAR = 0x4;
 
        ///<summary>
        ///设备控制块结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
           ///<summary>
            /// DCB长度
            ///</summary>
            public int DCBlength;
            ///<summary>
            ///指定当前波特率
            ///</summary>
            public int BaudRate;
            ///<summary>
            ///标志位
            ///</summary>
            public uint flags;
            ///<summary>
            ///未使用,必须为0
            ///</summary>
            public ushort wReserved;
            ///<summary>
            ///指定在XON字符发送这前接收缓冲区中可允许的最小字节数
            ///</summary>
            public ushort XonLim;
            ///<summary>
            ///指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数
            ///</summary>
            public ushort XoffLim;
            ///<summary>
            ///指定端口当前使用的数据位
            ///</summary>
            public byte ByteSize;
            ///<summary>
            ///指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 0-4=no,odd,even,mark,space
            ///</summary>
            public byte Parity;
            ///<summary>
            ///指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 0,1,2 = 1, 1.5, 2
            ///</summary>
            public byte StopBits;
            ///<summary>
            ///指定用于发送和接收字符XON的值 Tx and Rx XON character
            ///</summary>
            public byte XonChar;
            ///<summary>
            ///指定用于发送和接收字符XOFF值 Tx and Rx XOFF character
            ///</summary>
            public byte XoffChar;
            ///<summary>
            ///本字符用来代替接收到的奇偶校验发生错误时的值
            ///</summary>
            public byte ErrorChar;
            ///<summary>
            ///当没有使用二进制模式时,本字符可用来指示数据的结束
            ///</summary>
            public byte EofChar;
            ///<summary>
            ///当接收到此字符时,会产生一个事件
            ///</summary>
            public byte EvtChar;
            ///<summary>
            ///未使用
            ///</summary>
            public ushort wReserved1;
        }
 
        ///<summary>
        ///串口超时时间结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;
            public int ReadTotalTimeoutMultiplier;
            public int ReadTotalTimeoutConstant;
            public int WriteTotalTimeoutMultiplier;
            public int WriteTotalTimeoutConstant;
        }
 
        ///<summary>
        ///溢出缓冲区结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }
 
        ///<summary>
        ///打开串口
        ///</summary>
        ///<param name="lpFileName">要打开的串口名称</param>
        ///<param name="dwDesiredAccess">指定串口的访问方式,一般设置为可读可写方式</param>
        ///<param name="dwShareMode">指定串口的共享模式,串口不能共享,所以设置为0</param>
        ///<param name="lpSecurityAttributes">设置串口的安全属性,WIN9X下不支持,应设为NULL</param>
        ///<param name="dwCreationDisposition">对于串口通信,创建方式只能为OPEN_EXISTING</param>
        ///<param name="dwFlagsAndAttributes">指定串口属性与标志,设置为FILE_FLAG_OVERLAPPED(重叠I/O操作),指定串口以异步方式通信</param>
        ///<param name="hTemplateFile">对于串口通信必须设置为NULL</param>
        [DllImport(DLLPATH)]
        private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,
        int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
 
        ///<summary>
        ///得到串口状态
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpDCB">设备控制块DCB</param>
        [DllImport(DLLPATH)]
        private static extern bool GetCommState(int hFile, ref DCB lpDCB);
 
        ///<summary>
        ///建立串口设备控制块(嵌入版没有)
        ///</summary>
        ///<param name="lpDef">设备控制字符串</param>
        ///<param name="lpDCB">设备控制块</param>
        //[DllImport(DLLPATH)]
        //private static extern bool BuildCommDCB(string lpDef, ref DCB lpDCB);
 
        ///<summary>
        ///设置串口状态
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpDCB">设备控制块</param>
        [DllImport(DLLPATH)]
        private static extern bool SetCommState(int hFile, ref DCB lpDCB);
 
        ///<summary>
        ///读取串口超时时间
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpCommTimeouts">超时时间</param>
        [DllImport(DLLPATH)]
        private static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
 
        ///<summary>
        ///设置串口超时时间
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpCommTimeouts">超时时间</param>
        [DllImport(DLLPATH)]
        private static extern bool SetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
 
        ///<summary>
        ///读取串口数据
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpBuffer">数据缓冲区</param>
        ///<param name="nNumberOfBytesToRead">多少字节等待读取</param>
        ///<param name="lpNumberOfBytesRead">读取多少字节</param>
        ///<param name="lpOverlapped">溢出缓冲区</param>
        [DllImport(DLLPATH)]
        private static extern bool ReadFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToRead,
        ref int lpNumberOfBytesRead, ref OVERLAPPED lpOverlapped);
 
        ///<summary>
        ///写串口数据
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpBuffer">数据缓冲区</param>
        ///<param name="nNumberOfBytesToWrite">多少字节等待写入</param>
        ///<param name="lpNumberOfBytesWritten">已经写入多少字节</param>
        ///<param name="lpOverlapped">溢出缓冲区</param>
        [DllImport(DLLPATH)]
        private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite,
        ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped);
 
        [DllImport(DLLPATH, SetLastError = true)]
        private static extern bool FlushFileBuffers(int hFile);
 
        [DllImport(DLLPATH, SetLastError = true)]
        private static extern bool PurgeComm(int hFile, uint dwFlags);
 
        ///<summary>
        ///关闭串口
        ///</summary>
        ///<param name="hObject">通信设备句柄</param>
        [DllImport(DLLPATH)]
        private static extern bool CloseHandle(int hObject);
 
        ///<summary>
        ///得到串口最后一次返回的错误
        ///</summary>
        [DllImport(DLLPATH)]
        private static extern uint GetLastError();
        #endregion
 
        ///<summary>
        ///设置DCB标志位
        ///</summary>
        ///<param name="whichFlag"></param>
        ///<param name="setting"></param>
        ///<param name="dcb"></param>
        internal void SetDcbFlag(int whichFlag, int setting, DCB dcb)
        {
            uint num;
            setting = setting << whichFlag;
            if ((whichFlag == 4) || (whichFlag == 12))
            {
                num = 3;
            }
            else if (whichFlag == 15)
            {
                num = 0x1ffff;
            }
            else
            {
                num = 1;
            }
            dcb.flags &= ~(num << whichFlag);
            dcb.flags |= (uint)setting;
        }
 
        ///<summary>
        ///建立与串口的连接
        ///</summary>
        public int Open()
        {
            DCB dcb = new DCB();
            COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
 
            // 打开串口
            hComm = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
            if (hComm == INVALID_HANDLE_VALUE)
            {
                return -1;
            }
            // 设置通信超时时间
            GetCommTimeouts(hComm, ref ctoCommPort);
            ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            SetCommTimeouts(hComm, ref ctoCommPort);
 
            //设置串口参数
            GetCommState(hComm, ref dcb);
            dcb.DCBlength = Marshal.SizeOf(dcb);
            dcb.BaudRate = BaudRate;
            dcb.flags = 0;
            dcb.ByteSize = (byte)ByteSize;
            dcb.StopBits = StopBits;
            dcb.Parity = (byte)Parity;
 
            //------------------------------
            SetDcbFlag(0, 1, dcb);            //二进制方式
            SetDcbFlag(1, (Parity == 0) ? 0 : 1, dcb);
            SetDcbFlag(2, 0, dcb);            //不用CTS检测发送流控制
            SetDcbFlag(3, 0, dcb);            //不用DSR检测发送流控制
            SetDcbFlag(4, 0, dcb);            //禁止DTR流量控制
            SetDcbFlag(6, 0, dcb);            //对DTR信号线不敏感
            SetDcbFlag(9, 1, dcb);            //检测接收缓冲区
            SetDcbFlag(8, 0, dcb);            //不做发送字符控制
            SetDcbFlag(10, 0, dcb);           //是否用指定字符替换校验错的字符
            SetDcbFlag(11, 0, dcb);           //保留NULL字符
            SetDcbFlag(12, 0, dcb);           //允许RTS流量控制
            SetDcbFlag(14, 0, dcb);           //发送错误后,继续进行下面的读写操作
            //--------------------------------
            dcb.wReserved = 0;                       //没有使用,必须为0      
            dcb.XonLim = 0;                          //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数
            dcb.XoffLim = 0;                         //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数
            dcb.XonChar = 0;                         //发送和接收的XON字符
            dcb.XoffChar = 0;                        //发送和接收的XOFF字符
            dcb.ErrorChar = 0;                       //代替接收到奇偶校验错误的字符
            dcb.EofChar = 0;                         //用来表示数据的结束     
            dcb.EvtChar = 0;                         //事件字符,接收到此字符时,会产生一个事件       
            dcb.wReserved1 = 0;                      //没有使用
 
            if (!SetCommState(hComm, ref dcb))
            {
                return -2;
            }
            Opened = true;
            return 0;
        }
        ///<summary>
        ///关闭串口,结束通讯
        ///</summary>
        public void Close()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hComm);
            }
        }
        ///<summary>
        ///读取串口返回的数据
        ///</summary>
        ///<param name="NumBytes">数据长度</param>
        public int Read(ref byte[] bytData, int NumBytes)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesRead = 0;
                ReadFile(hComm, bytData, NumBytes, ref BytesRead, ref ovlCommPort);
                return BytesRead;
            }
            else
            {
                return -1;
            }
        }
 
        ///<summary>
        ///向串口写数据
        ///</summary>
        ///<param name="WriteBytes">数据数组</param>
        public int Write(byte[] WriteBytes, int intSize)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesWritten = 0;
                WriteFile(hComm, WriteBytes, intSize, ref BytesWritten, ref ovlCommPort);
                return BytesWritten;
            }
            else
            {
                return -1;
            }
        }
 
        ///<summary>
        ///清除接收缓冲区
        ///</summary>
        ///<returns></returns>
        public void ClearReceiveBuf()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR);
            }
        }
 
        ///<summary>
        ///清除发送缓冲区
        ///</summary>
        public void ClearSendBuf()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR);
            }
        }
 }
后记:我的串口程序修改为API方式后,实际发现与SerialPort类遇到同样的问题,所以SerialPort类还是值得信任的。该API方式的代码在WinCE平台和PC平台都调试通过。 

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

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

相关文章

数据可视化工具_数据可视化

数据可视化工具Visualizations are a great way to show the story that data wants to tell. However, not all visualizations are built the same. My rule of thumb is stick to simple, easy to understand, and well labeled graphs. Line graphs, bar charts, and histo…

Android Studio调试时遇见Install Repository and sync project的问题

我们可以看到&#xff0c;报的错是“Failed to resolve: com.android.support:appcompat-v7:16.”&#xff0c;也就是我们在build.gradle中最后一段中的compile项内容。 AS自动生成的“com.android.support:appcompat-v7:16.”实际上是根据我们的最低版本16来选择16.x.x及以上编…

Apache Ignite 学习笔记(二): Ignite Java Thin Client

前一篇文章&#xff0c;我们介绍了如何安装部署Ignite集群&#xff0c;并且尝试了用REST和SQL客户端连接集群进行了缓存和数据库的操作。现在我们就来写点代码&#xff0c;用Ignite的Java thin client来连接集群。 在开始介绍具体代码之前&#xff0c;让我们先简单的了解一下Ig…

VGAE(Variational graph auto-encoders)论文及代码解读

一&#xff0c;论文来源 论文pdf Variational graph auto-encoders 论文代码 github代码 二&#xff0c;论文解读 理论部分参考&#xff1a; Variational Graph Auto-Encoders&#xff08;VGAE&#xff09;理论参考和源码解析 VGAE&#xff08;Variational graph auto-en…

IIS7设置

IIS 7.0和IIS 6.0相比改变很大谁都知道&#xff0c;而且在IIS 7.0中用VS2005来调试Web项目也不是什么新鲜的话题&#xff0c;但是我还是第一次运用这个东东&#xff0c;所以在此记下我的一些过程&#xff0c;希望能给更多的后来者带了一点参考。其实我写这篇文章时也参考了其他…

tableau大屏bi_Excel,Tableau,Power BI ...您应该使用什么?

tableau大屏biAfter publishing my previous article on data visualization with Power BI, I received quite a few questions about the abilities of Power BI as opposed to those of Tableau or Excel. Data, when used correctly, can turn into digital gold. So what …

python 可视化工具_最佳的python可视化工具

python 可视化工具Disclaimer: I work for Datapane免责声明&#xff1a;我为Datapane工作 动机 (Motivation) There are amazing articles on data visualization on Medium every day. Although this comes at the cost of information overload, it shouldn’t prevent you …

网络编程 socket介绍

Socket介绍 Socket是应用层与TCP/IP协议族通信的中间软件抽象层&#xff0c;它是一组接口。在设计模式中&#xff0c;Socket其实就是一个门面模式&#xff0c;它把复杂的TCP/IP协议族隐藏在Socket接口后面&#xff0c;对用户来说&#xff0c;一组简单的接口就是全部。 Socket通…

猿课python 第三天

字典 字典是python中唯一的映射类型,字典对象是可变的&#xff0c;但是字典的键是不可变对象&#xff0c;字典中可以使用不同的键值字典功能> dict.clear()          -->清空字典 dict.keys()          -->获取所有key dict.values()      …

在C#中使用代理的方式触发事件

事件&#xff08;event&#xff09;是一个非常重要的概念&#xff0c;我们的程序时刻都在触发和接收着各种事件&#xff1a;鼠标点击事件&#xff0c;键盘事件&#xff0c;以及处理操作系统的各种事件。所谓事件就是由某个对象发出的消息。比如用户按下了某个按钮&#xff0c;某…

BP神经网络反向传播手动推导

BP神经网络过程&#xff1a; 基本思想 BP算法是一个迭代算法&#xff0c;它的基本思想如下&#xff1a; 将训练集数据输入到神经网络的输入层&#xff0c;经过隐藏层&#xff0c;最后达到输出层并输出结果&#xff0c;这就是前向传播过程。由于神经网络的输出结果与实际结果…

使用python和pandas进行同类群组分析

背景故事 (Backstory) I stumbled upon an interesting task while doing a data exercise for a company. It was about cohort analysis based on user activity data, I got really interested so thought of writing this post.在为公司进行数据练习时&#xff0c;我偶然发…

3.Contructor(构造器)模式—精读《JavaScript 设计模式》Addy Osmani著

同系列友情链接: 1.设计模式之初体验—精读《JavaScript 设计模式》Addy Osmani著 2.设计模式的分类—精读《JavaScript 设计模式》Addy Osmani著 Construct&#xff08;构造器&#xff09;模式 在经典的面向对象编程语言中&#xff0c;Construtor是一种在内存已分配给该对象的…

BZOJ 3653: 谈笑风生(离线, 长链剖分, 后缀和)

题意 给你一颗有 \(n\) 个点并且以 \(1\) 为根的树。共有 \(q\) 次询问&#xff0c;每次询问两个参数 \(p, k\) 。询问有多少对点 \((p, a, b)\) 满足 \(p,a,b\) 为三个不同的点&#xff0c;\(p, a\) 都为 \(b\) 的祖先&#xff0c;且 \(p\) 到 \(a\) 的距离不能超过 \(k\) 。 …

搜索引擎优化学习原理_如何使用数据科学原理来改善您的搜索引擎优化工作

搜索引擎优化学习原理Search Engine Optimisation (SEO) is the discipline of using knowledge gained around how search engines work to build websites and publish content that can be found on search engines by the right people at the right time.搜索引擎优化(SEO…

Siamese网络(孪生神经网络)详解

SiameseFCSiamese网络&#xff08;孪生神经网络&#xff09;本文参考文章&#xff1a;Siamese背景Siamese网络解决的问题要解决什么问题&#xff1f;用了什么方法解决&#xff1f;应用的场景&#xff1a;Siamese的创新Siamese的理论Siamese的损失函数——Contrastive Loss损失函…

Dubbo 源码分析 - 服务引用

1. 简介 在上一篇文章中&#xff0c;我详细的分析了服务导出的原理。本篇文章我们趁热打铁&#xff0c;继续分析服务引用的原理。在 Dubbo 中&#xff0c;我们可以通过两种方式引用远程服务。第一种是使用服务直联的方式引用服务&#xff0c;第二种方式是基于注册中心进行引用。…

期权价格的上限和下限

期权按照买方权利性质分为&#xff1a;看涨期权和看跌期权 1、首先&#xff0c;看涨期权的上限和下限 看涨期权价格上限为其标的资产价格。 看涨期权是给予买方一个在未来买入标的资产的权利&#xff0c;如果该权利的价格高于标的资产的价格&#xff0c;那么投资者不如直接购买…

一件登录facebook_我从Facebook的R教学中学到的6件事

一件登录facebookBetween 2018 to 2019, I worked at Facebook as a data scientist — during that time I was involved in developing and teaching a class for R beginners. This was a two-day course that was taught about once a month to a group of roughly 15–20 …

SiameseFC超详解

SiameseFC前言论文来源参考文章论文原理解读首先要知道什么是SOT&#xff1f;&#xff08;Siamese要做什么&#xff09;SiameseFC要解决什么问题&#xff1f;SiameseFC用了什么方法解决&#xff1f;SiameseFC网络效果如何&#xff1f;SiameseFC基本框架结构SiameseFC网络结构Si…