線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2424
推到 Plurk!
推到 Facebook!

PAnsiChar 與 String 轉換問題spcomm 元件

答題得分者是:aftcast
weiliching
初階會員


發表:53
回覆:77
積分:31
註冊:2003-12-27

發送簡訊給我
#1 引用回覆 回覆 發表時間:2015-03-17 11:40:06 IP:42.119.xxx.xxx 訂閱
Dear 高手們:
我參考了 ,
http://delphi.ktop.com.tw/board.php?cid=169&fid=1015&tid=105074
修改了Spcomm 元件, 在傳送與接收都不會有問題 ,在傳送時.經過了PAnsiChar 傳送
但是我如果在傳送時改 成了"變數" 就會開始有問題
也就是
Var PAnsiChar
Begin
S:= ':01606495';
我用Watch list 去看S的參數變化是ok的,
但是我改成
Var PAnsiChar
Begin
S:= PAnsiChar(':016' '06495');
在去看S Waitch List 變化就會出問題
資料就會傳不過去
我發現到我的 問題是跟這大大題的問題一樣
http://delphi.ktop.com.tw/board.php?cid=30&fid=1498&tid=105543
但是因為我不能給他固定參數,
我的內容是一定要會變的String;

原始 程式 M_TenToChk 是自己寫的附程式,會把某Edit1.txt 轉換成String 相對需要的資料給我
主要功能是將他轉成2的補數. 16進位"
原始寫法如下:
Var S:PAnsiChar;
M_CHK :String;
begin
M_Chk := M_Public.TenToChk(StrTointDef(Edit1.Text,0)*10);
s:= PAnsiChar(':0106' '0000' '0' M_Chk #13 #10);
// s:= ':0106' '0000' '0' '06495' #13 #10;//改成這樣沒問題
Comm1.WriteCommData(s,Length(s));

附加檔案:5507a216a9060_4.JPG
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2015-03-17 12:26:38 IP:114.32.xxx.xxx 訂閱
please try as following:

var astr:AnsiString

astr := ':0106' '0000' '0' M_Chk #13 #10;

Comm1.WriteCommData(PAnsichar(astr),Length(astr));


------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
weiliching
初階會員


發表:53
回覆:77
積分:31
註冊:2003-12-27

發送簡訊給我
#3 引用回覆 回覆 發表時間:2015-03-19 19:08:24 IP:113.161.xxx.xxx 訂閱


感謝回覆~改成這樣就沒問題~
但是弄不懂為何會這樣呢?
測試過很多方式~可能是對這些變數不瞭解~
有參考過 PChar 與 String 知道儲存的方式不同.

能否有高手對這些參 至於AnsiString 與PAnsiChar,,,String 三個 差別.與?
一直也弄不清?


===================引 用 aftcast 文 章===================
please try as following:

var astr:AnsiString

astr := ':0106' '0000' '0' M_Chk #13 #10;

Comm1.WriteCommData(PAnsichar(astr),Length(astr));


aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2015-03-20 02:27:03 IP:111.243.xxx.xxx 訂閱
String 在 d2009 版前是 AnsiString的別名,在 d2009(含)後是UnicodeString的別名。

AnsiString 是一個「容器」,裡面可以放字元,且容器裡存放的基本單位是一個byte。所謂的基本單位影響著AnsiString相關的函式對AnsiString的處理方式。

UnicodeString 是一個「容器」,裡面可以放字元,且容器裡存放的基本單位是二個byte。所謂的基本單位影響著UnicodeString 相關的函式對UnicodeString 的處理方式。

PChar 在 d2009前是一個指標(pointer),指向 AnsiString這個容器,相當於PAnsiChar ; 在 d2009後,則是指向UnicodeString容器。

何謂指標/針? (pointer) : 對於學c/c 語言的人理當都會懂。delphi也有指標,但很少人用心去懂、去用。請google查這方面的知識,假使你不太明白 pointer的話。但在這裡,簡單的說,它不是容器,它裡面放的只是一個記憶體(內存)的位址,該位址就是真的放資料(如,字串)的地方。(也就是容器的所在)。

中文字,用big5編碼時,是使用AnsiString容器來裝字元。即使big5的中文是2個bytes,但big5編碼下的英文部份依然是1個byte。而AnsiString的基本存放單位就是1個byte,所以專門拿來存這類的編碼。

中文字,用unicode (ucs2,utf16,但非utf8)的編碼時,因無論中文或是英文,都是占二個bytes,所以要用UnicodeString來裝,這樣字取用時,總是一次拿2個bytes出來。

windows 32 api 都是 c 語言寫的,所以許多的參數都是指標。所以幾乎是用PChar,或是PAnsiChar的型別來傳入給它用。由於你用的是rs232之類的通訊協定,照我多年經驗,都是處理以 1 byte為單位的一串資訊,即使是中文,通常也是big5編碼。故這種情形下,理當然用AnsiString來裝這些資料最恰當。

解說完精華,就讓我來說你的問題所在:

說來有點小複雜,但我有限的時間就稍粗的說。你的那行

':0106' '0000' '0' M_Chk #13 #10;
compiler大概是這樣處理的:
1/暫時建一個 string 容器,把那一堆字串加好後,放入這個暫時string裡。
2/ 因為你的變數是一個 PAnsiChar,所以compiler就為你建一個暫時的PAnsiChar的指標,並指向暫時的那個string容器
3/ 準備出錯了……
當那一行程式執行完,跳至下一行時,那暫時的string容器會自動刪除 (否則就不會叫暫時),至於刪除的情形又可以分很多種情形,不過,你先別去了解,未來再說。你就當它會被清,僅管「有些時候,看起來似乎沒清,但千萬別心存僥倖」。
於是那個PAnsiChar所指的地方已經不是該有的內容。

解法:

我教你的作法就是,乖乖的把那些資串加入後放進一個AnsiString區域變數,這樣就可以保持它一直完好,直到跳出函式。而在它需要被使用指標送出時,再強轉型別即可。

給你的幾個建議:

1/ 儘量不要宣告PChar/PAnsiChar的型別變數,除非你真的很懂它。而真的需要它時,只要強轉型別即可。但記得D2009後,PChar 與 String (unicodestring)是一對的。 AnsiString與PAnsiChar是一對的。所謂的一對,就是你別試著把 String 轉 PAnsiChar 可能會出錯。除非你真的很了解編碼,不然就是用成對的來轉型。
2/ 計算字串長度,理當裡面放的是容器,而非指標。僅管delphi可能會幫你從指標想辦法找到容器,進一步算出長度,但這樣極度不可靠,要避免!
3/ 我以上所言,真的是句句重點,且是多年的心得,若可能,請務必每句都去了解我在說什麼。這樣應該就不會又忘記。



------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
weiliching
初階會員


發表:53
回覆:77
積分:31
註冊:2003-12-27

發送簡訊給我
#5 引用回覆 回覆 發表時間:2015-03-20 14:41:48 IP:42.119.xxx.xxx 訂閱
謝謝aftcast 站務副站長解說~
說的很詳細..也說到了精華與重點.
以前在Dos 時代學 C時~就常用指標, 所以對指標用法, 還是清楚
謝謝以上的解說..只是遇到這些後期的Delphi 版本.. 書越來越少.
有機會要把這些在努力

B,Rgds
Vincent wei


===================引 用 aftcast 文 章===================
String 在 d2009 版前是 AnsiString的別名,在 d2009(含)後是UnicodeString的別名。

AnsiString 是一個「容器」,裡面可以放字元,且容器裡存放的基本單位是一個byte。所謂的基本單位影響著AnsiString相關的函式對AnsiString的處理方式。

UnicodeString 是一個「容器」,裡面可以放字元,且容器裡存放的基本單位是二個byte。所謂的基本單位影響著UnicodeString 相關的函式對UnicodeString 的處理方式。

PChar 在 d2009前是一個指標(pointer),指向 AnsiString這個容器,相當於PAnsiChar ; 在 d2009後,則是指向UnicodeString容器。

何謂指標/針? (pointer) : 對於學c/c 語言的人理當都會懂。delphi也有指標,但很少人用心去懂、去用。請google查這方面的知識,假使你不太明白 pointer的話。但在這裡,簡單的說,它不是容器,它裡面放的只是一個記憶體(內存)的位址,該位址就是真的放資料(如,字串)的地方。(也就是容器的所在)。

中文字,用big5編碼時,是使用AnsiString容器來裝字元。即使big5的中文是2個bytes,但big5編碼下的英文部份依然是1個byte。而AnsiString的基本存放單位就是1個byte,所以專門拿來存這類的編碼。

中文字,用unicode (ucs2,utf16,但非utf8)的編碼時,因無論中文或是英文,都是占二個bytes,所以要用UnicodeString來裝,這樣字取用時,總是一次拿2個bytes出來。

windows 32 api 都是 c 語言寫的,所以許多的參數都是指標。所以幾乎是用PChar,或是PAnsiChar的型別來傳入給它用。由於你用的是rs232之類的通訊協定,照我多年經驗,都是處理以 1 byte為單位的一串資訊,即使是中文,通常也是big5編碼。故這種情形下,理當然用AnsiString來裝這些資料最恰當。

解說完精華,就讓我來說你的問題所在:

說來有點小複雜,但我有限的時間就稍粗的說。你的那行

':0106' '0000' '0' M_Chk #13 #10;
compiler大概是這樣處理的:
1/暫時建一個 string 容器,把那一堆字串加好後,放入這個暫時string裡。
2/ 因為你的變數是一個 PAnsiChar,所以compiler就為你建一個暫時的PAnsiChar的指標,並指向暫時的那個string容器
3/ 準備出錯了……
當那一行程式執行完,跳至下一行時,那暫時的string容器會自動刪除 (否則就不會叫暫時),至於刪除的情形又可以分很多種情形,不過,你先別去了解,未來再說。你就當它會被清,僅管「有些時候,看起來似乎沒清,但千萬別心存僥倖」。
於是那個PAnsiChar所指的地方已經不是該有的內容。

解法:

我教你的作法就是,乖乖的把那些資串加入後放進一個AnsiString區域變數,這樣就可以保持它一直完好,直到跳出函式。而在它需要被使用指標送出時,再強轉型別即可。

給你的幾個建議:

1/ 儘量不要宣告PChar/PAnsiChar的型別變數,除非你真的很懂它。而真的需要它時,只要強轉型別即可。但記得D2009後,PChar 與 String (unicodestring)是一對的。 AnsiString與PAnsiChar是一對的。所謂的一對,就是你別試著把 String 轉 PAnsiChar 可能會出錯。除非你真的很了解編碼,不然就是用成對的來轉型。
2/ 計算字串長度,理當裡面放的是容器,而非指標。僅管delphi可能會幫你從指標想辦法找到容器,進一步算出長度,但這樣極度不可靠,要避免!
3/ 我以上所言,真的是句句重點,且是多年的心得,若可能,請務必每句都去了解我在說什麼。這樣應該就不會又忘記。



系統時間:2017-10-19 20:29:18
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!