C 星座星盤計算演算法

2021-07-25 17:50:44 字數 4167 閱讀 5832

在**之前,筆者先分享一些基本知識,首先是12星座。

其次是星和行星

上面的太陽(sun)和月亮(moon)就不必解釋了,其他的行星都給出了英文名、符號和解釋。網路的圖沒有冥王星英文是(pluto)。

好了開始**部分,首先我們要新增用於c#訪問的函式,

#define api_export __declspec(dllexport)

先這裡做個預定義,後面每個函式都要用到。使用功能之前要先給astrolog程式來做個初始化

extern_c api_export void __stdcall init()

初始化好了就可以呼叫實質的函式來生成星圖,儲存星圖到資料夾,並把右側資料資訊儲存到字串來返回

extern_c api_export wchar_t* __stdcall processastrolog(wchar_t* filepath, int year, int month,int day,double time)

;char *v0 = "astrolog";

char *v1 = "-xo";

char *v2 = w2c(filepath);

if (v2 == null) return null;

char * vs = ;

i= fprocessswitches(3, vs);

action();

sprintf(result, "%s", allinfo);

free(v2);

v2 = null;

free(allinfo);

allinfo = null;

return c2w( result);

}extern_c api_export int __stdcall freesmem(wchar_t* intptr)

這裡面還涉及到c#的char是用2個位元組來儲存的而在c++裡面char是用1個位元組來儲存的,從這裡大家也可以理解為什麼筆者放棄在c++裡面直接漢化輸出了。既然有這麼個gap,我們就需要做轉換工作,c#裡面的char對應著c++裡面的wchar_t,傳進來之後要把高位的扔掉,生成乙個長度相等,每位是c++的char大小的空間來存放新字串,反之從c++的字串傳到c#的也要做一次這樣的反操作。大家可以不理解,直接拷貝下面的**用就是了。上面的freesmem函式是因為返回的字串內容要在c#裡面用完了才能銷毀,所以有這個函式供c#來呼叫並銷毀。

wchar_t* c2w(char* cstr)

char* w2c(wchar_t* wstr)

上面的c2w和w2c裡面的c和w分別代表c++的char和wchar_t。

好了可以介紹上面這個processastrolog()函式了,首先給allinfo 分配了一段記憶體來儲存右側資料資訊用來返回到c#,然後更新使用者資料報括年月日時間等的資訊,即更新cicore變數,接著模擬執行一條儲存星圖的命令,這個其實大家可以使用cmd嘗試執行astrolog.exe -xo d:\abc.bmp這樣的語句,就知道本函式的方法了。傳進去後儲存並不是立刻執行的,所以需要加入action()這一句來儲存,最後釋放指標並返回字串結果。

然後就到c#**了,見下面

[dllimport(@"astrolog.dll")]

extern unsafe static void init();

[dllimport(@"astrolog.dll")]

extern unsafe static intptr processastrolog(char* filepath, int year, int month, int day, double time);

先定義dllimport,這個不難。

void processastrolog()

this.richtextbox1.text += marshal.ptrtostringauto(abc);

freeresult= freesmem(abc);}}

if (file.exists(filepath))

messagebox.show(freeresult.tostring());

}catch

}然後要先建1個鏈結字串,固化到記憶體並把記憶體首位址傳進dll,如果用過c#做影象處理的應該對鎖記憶體很熟悉吧。然後把位址,年月日時間等傳進dll,獲取返回的字串連線,並輸出到文字框,因為這個字串所在的記憶體是c++裡面動態開闢的,所以需要釋放,最後載入就可以了。

c++修改專案屬性為輸出dll而不是exe,修改c#的項

目屬性,將目標平台設定為x86,並且允許非安全**。

一切都很不錯,成功執行,成功儲存並返回字串結果。可惜的是,執行不了多久就會記憶體報錯,這真的是百思不得其解的鬱悶事,筆者怎麼說寫**15年了也是混過c和c++的,包括微控制器的彙編,記憶體管理大家都知道是個頭疼事不過筆者還是挺自信的,仔細檢查一下,所有的malloc之後都free了,並設定指標指向null了,c#裡面也把**都放進try catch裡面了,還是報錯,而且記憶體錯誤是致命的不可能繼續執行。

萬般無奈之下,筆者開始了另一種方式,在c#裡面開闢記憶體位址存放返回的字串傳給c++,而c++裡面的只要有malloc那麼在返回到c#之前就free掉,並且做了工作狀態的限制,新建1個布林型別的全域性變數叫dllprocessing,在程式開始的時候才賦值為真程式末尾賦值為假,在為真的狀態下allinfo才能夠被操作,即if(dllprocessing) strcat(allinfo, sz);。並且讓c#的unsafe裡面的**盡量少,最後**如下

dllprocessing = true;

allinfo = resultstring;

/* month, day, year, time in hours, daylight offset, time zone, longitude, latitude, name for chart, name of location */

cicore = ;

char *v0 = "astrolog";

char *v1 = "-xo";

char *v2 = w2c(filepath);

if (v2 == null) return null;

char * vs = ;

fprocessswitches(3, vs);

action();

dllprocessing = false;

free(v2);

v2 = null;

return allinfo;

c#**如下

byte bpara = new byte[2000];    //新建位元組陣列  

intptr pret;

unsafe

}if (pret == null)

string strget = system.text.encoding.default.getstring(bpara, 0, bpara.length);    //將位元組陣列轉換為字串  

string strret = marshal.ptrtostringansi(pret);

this.richtextbox1.text += strret;

這次就好了,沒有深究前面**記憶體出錯的原因,估計是在c++ malloc的字串指標在返回到c#之後沒有立即銷毀,而這段時間c++裡面的函式在看不見的地方有沒有呼叫過不知道,畢竟c++的**並沒有深入去研究,那麼在c#去釋放這段位址的時候可能它已經改變了,就出錯了。所以建議是,自己在c++額外植入的**,用了malloc在自己可預見的範圍內就要銷毀,否則c++原有部分就是個黑匣子,你都不知道會發生什麼。

可以獲得所有需要的資料了,這裡輸出的資料經過筆者篩選,沒用的不輸出,然後可以根據這些資料來做自己想做的事情了。最後要給大家介紹另一位大師的文章也是研究astrolog的,和**沒關係,不過可以獲得不少星盤研究的知識,

計算星座演算法解析

本程式對星座的計算是以公曆為準,計算的方式多種多樣,下面介紹一種計算星座的方法 以通過判斷和計算得到陣列對應的索引來找到星座 import define num n nsnumber numberwithint n 乙個巨集,用來封裝整型數為nsnumber型別的物件,方便存入nsarray的陣列中...

計算演算法複雜度

演算法的複雜度分為時間複雜度和空間複雜度 1.時間複雜度 在計算演算法複雜度時一般只用到大o符號,landau符號體系中的小o符號 符號等等比較不常用。這裡的o,最初是用大寫希臘字母,但現在都用大寫英語字母o 小o符號也是用小寫英語字母o,符號則維持大寫希臘字母 常見的演算法時間複雜度由小到大依次為...

分頁頁碼計算演算法

最近做 用到了分頁頁碼計算的演算法,覺得之前一直用的不好,自己寫了乙個,拿出來與大家共享一下 view code 1 package cnblogs.xiaoqiu.test 23 4 1.如果是5個可見頁碼,1 12345,2 12345,3 12345,4 23456,5 34567,6 456...