2021年3月30日 星期二

Git 版本管控(一)-淺談版本管控

最近,部門說要導入這個,然後由我做教學?!?!,既然都這樣安排了,就來整理自己目前對Git的了解,預計分享的內容如下:
  1. 淺談版本管控
  2. Git的環境建置
  3. Git本機操作
  4. Git遠端操作
淺談版本管控(Version Control)
首先,為什麼要使用版本管控(Version Control)呢?說說自己以前在研究所時期,剛開始寫C/C++跟OpenCV時,往往就是修改了一下程式或寫一些功能之後,為了避免後續程式碼可能被改到不能用,就會加上時間做區隔,類似做備份使用,但久而久之備份的內容越來越多,有時想還原回正常版本卻忘記不知哪邊被改動,因為距離上次修改太久了,所以只能細部查找差異性,間接花了很多時間在做非功能性開發,這個狀況持續到我工作接觸到Git才有所改變,此時發現原來寫軟體除了邏輯要夠用之外,其實蠻多小工具也要學會,因為正式的專案其架構都蠻大的,所以工作上會切分成寫人機介面(前端)演算法(後端)而某方寫完功能後一定會做測試,後續並做整合測試等等,因此若用改時間或註解紀錄程式碼修改差異,其效率或除錯速度都不好,所以才會出現版本管控(Version Control)這個概念。

更進一步的說,寫程式除了功能寫完之外,一般還會有整合、測試、進版等等,所以不是單單寫完程式就沒事!!畢竟如果寫出一堆Bug給別人就尷尬了,或是自己未來要除錯也不容易,總結來說版本管控(Version Control)就是用來記錄程式碼每次更改的差異,並能協助我們紀錄特定版本,若出現某版本因修改後而不穩定時,還能還原先前穩定版本,同時能找到是誰偷放這個臭蟲,哈哈哈哈,然後發現原來是自己搞的鬼!

版本管控系統(Version Control Systems)
    版本管控常用的工具,可分為集中式(Centralized Version Control Systems)與分散式(Distributed Version Control Systems),集中式顧名思義就是說將其程式碼存放在遠端的伺服器(Server),因此每次的提交(Commit)都必須要連到這個伺服器(Server)才行,本機端是無法做提交(Commit)動作,同時企業使用時可能要付費,若伺服器(Server)不小心發生什麼毀損,程式碼可能就會不翼而飛,其架構如下:



    相反的分散式則可以在本機端進行提交(Commit),同時也能夠上傳(push)到伺服器(Server),以我來看其實分散式的伺服器(Server)也可以視為是一種本機,只是相對於我們它是遠端而已,重點是它是免費的,免錢的最好啦!!其架構如下所示


後續會以分散式管控的Git做教學,預計會說明如何搭配Gui+Git做使用~~

2021年3月20日 星期六

C# 使用C++ DLL檔(回傳值)

延續上篇(C# 使用C++ DLL檔)之後,一般使用DLL時,除了將參數提供給DLL演算法做使用,也需將演算法結果從DLL回傳回去,所以這次就來說明如何回傳結果給C#吧。

目前我了解到如果要從DLL回傳結果給C#,都會使用指標做回傳,而我先前測試經驗,C++撰寫上比較不會遇到問題,但在接收端C#有遇過接不到數值、接錯值、或是跑久還造成程式當掉,重點是DLL除錯還不怎麼容易,像是瞎子摸象的感覺,如果有人知道怎樣較快除DLL的Bug,再歡迎留言告訴我,感謝!!!經過一番的測試之後,我目前可正常回傳的資訊分別為字串與float陣列資訊。

Extern.cpp

#ifdef SYSALGORITHM_EXPORTS
#define SYSALGORITHM_API __declspec(dllexport)
#include "SysAlgorithm.h"

extern "C" SYSALGORITHM_API int add(int a, int b)
{
	Calculator Calculator;
	return Calculator.add(a, b);
}

extern "C" SYSALGORITHM_API int subtract(int a, int b)
{
	Calculator Calculator;
	return Calculator.subtract(a, b);
}

extern "C" SYSALGORITHM_API void getDLLValue(float * DLLvalue)
{
	Calculator Calculator;
	return Calculator.getDLLValue(DLLvalue);
}

extern "C" SYSALGORITHM_API void getDLLInfo(char * DLLInfo)
{
	Calculator Calculator;
	return Calculator.getDLLInfo(DLLInfo);
}

#endif

SysAlgorithm.h

#pragma once
#ifndef SYSALGORITHM_H
#define SYSALGORITHM_H

#include <fstream>
#include <string>

class Calculator
{
public:
	Calculator();
	~Calculator();

	int add(int a, int b);
	int subtract(int a, int b);
	void getDLLValue(float * DLLvalue);
	void getDLLInfo(char * DLLInfo);
};

#endif // !SYSALGORITHM_H 

SysAlgorithm.cpp

#include "SysAlgorithm.h"

Calculator::Calculator()
{

}

Calculator::~Calculator()
{

}

int Calculator::add(int a, int b)
{
	return(a + b);
}

int Calculator::subtract(int a, int b)
{
	return(a - b);
}

void Calculator::getDLLValue(float * DLLvalue)
{
	DLLvalue[0] = 0;
	DLLvalue[1] = 1.2;
	DLLvalue[2] = -1.2;
}

void Calculator::getDLLInfo(char * DLLInfo)
{
	char Info[20] = "return DLLInfo";
	strcpy_s(DLLInfo, strlen(Info) + 1, Info);
} 

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SysUI
{
    public partial class Form1 : Form
    {
        [DllImport("SysAlgorithm.dll", EntryPoint = "add", CallingConvention = CallingConvention.Cdecl)]
        private static extern int add(int a, int b);

        [DllImport("SysAlgorithm.dll", EntryPoint = "subtract", CallingConvention = CallingConvention.Cdecl)]
        private static extern int subtract(int a, int b);

        [DllImport("SysAlgorithm.dll", EntryPoint = "getDLLValue", CallingConvention = CallingConvention.Cdecl)]
        private static extern void getDLLValue([MarshalAs(UnmanagedType.LPArray)]float[] value);

        [DllImport("SysAlgorithm.dll", EntryPoint = "getDLLInfo", CallingConvention = CallingConvention.Cdecl)]
        private static extern void getDLLInfo(StringBuilder DLLInfo);

        private StringBuilder DLLInfo = new StringBuilder(20);
        private float[] DLLvalue = new float[3];

        public Form1()
        {
            InitializeComponent();
            label1.Text = add(3, 5).ToString();
            label2.Text = subtract(3, 5).ToString();
            getDLLValue(DLLvalue);
            getDLLInfo(DLLInfo);
            label6.Text = DLLvalue[0].ToString() + "," + DLLvalue[1].ToString("F2") + "," + DLLvalue[2].ToString("F2");
            label8.Text = DLLInfo.ToString();
        }
    }
}
 
為了可以正確取得從DLL演算法回傳參數,C#的DllImport這邊很重要!!記得要注意


結果圖: