天天看點

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

今天是2020年5月2日,五一國際勞動節小長假的第二天。讓我們繼續勞動起來。

使用ABAP strlen函數計算下列這4個字元和字元串變量中包含的字元個數。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?
大家先别急着滑動螢幕,先試着自己計算一下,看和标準答案是否有出入。也許大家覺得這些小的知識點沒什麼用,但Jerry馬上會分享一個我實際處理過的客戶incident,正是由于類似這種看似不起眼的小知識點沒有留意,最後影響了項目進展。
關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?
關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?
關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

正确答案,依次是:

2

1

19

17

逐一解釋。

strlen( lv_s ) = 2

整型變量的值,整數1,賦給字元串變量lv_s, 這裡發生一個隐式類型轉換。

SAP幫助文檔裡聲明,整型變量賦給字元串變量時,如果整數為負數,則字元串變量末尾為"-";如果整數為正數,則字元串變量末尾為空白字元。換言之,當整型變量到字元串變量的隐式類型轉換發生時,字元串變量末尾會多出一位,代表指派源頭的整型數的符号位。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?
lv_s多出來的這個空白字元在調試器裡看得很清楚,2000正是空白字元的16進制編碼。同時調試器裡也能看到lv_s的字元串個數為2.
關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

strlen( lv_s2 ) = 1

和前一例相比,lv_s2的複制操作沒有出現隐式類型轉換,而是直接被賦以了一個字元常量,故字元個數為1.

strlen( lv_ss) = 19

lv_ss的類型為SSTRING,實際就是一個CHAR20:

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

在調試器裡,lv_ss有18個前導空白(leading blank)字元,字元"1"和1個尾部空白(trailing blank)字元組成,總共20個字元,調試器裡的Technical Type顯示為C(20).

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

那為什麼strlen(lv_ss)不等于20,而等于19?SAP幫助文檔裡給出了答案——SSTRING即CHAR20這種變量,屬于固定長度(fixed length)類型變量。當使用strlen函數計算這種變量的字元串個數時,尾部空白字元不應參加計數,是以要減一。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

strlen( lv_s3) = 17

有了例三的基礎,這個就很容易了。變量lv_s3類型是CHAR18,屬于固定長度類型變量,是以strlen計算出的字元串個數為18 - 1 = 17.

第一個例子中,我們把一個整數直接賦給了一個字元串變量,發生了隐式類型轉換。在實際項目中,這種隐式類型轉換很容易出現在函數或者ABAP類方法的參數傳遞中。對于函數或ABAP類方法的形式參數,如果我們傳遞的實際參數類型和其類型不比對,就會發生隐式類型轉換,這種自動轉換有時并非我們期望發生的,甚至容易被忽略。

看一個真實的例子。我曾經擔任過一個俄羅斯的SAP CRM客戶項目的Dev Angel,收到過一個性能相關的incident,客戶打開某個UI的速度極其緩慢,甚至經常逾時。

我通過調試,最終發現罪魁禍首位于下段代碼。該代碼從SAP CRM發起RFC調用,去SAP ERP讀取資料,Max Hit設定為15,意思是期望ERP端至多傳回15條記錄。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

然而從ERP端傳回了總共408093條記錄。顯然,雖然通過寫死指定Max Hit為15,卻完全沒有起到限制作用。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

起初我想當然地認為這是ERP函數的bug,沒有正确處理CRM調用端傳遞過來的Max Hit. 然而當我在調試器裡單步執行到CRM函數内部檢視iv_max_entries時,一下傻了眼:

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

它的值從15一下變成了3473457. 這個數字是什麼鬼?!

再看函數的形式參數定義,iv_max_entries類型為整型,而二次開發顧問傳入的寫死值’15’, 是一個字元值,我頓時恍然大悟。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

'15’是怎麼變成魔幻數字3473457的?

Jerry先不解釋,而是請大家看下面這段代碼:

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

執行,正好輸出3473457這個魔幻數字。那麼代碼第四行31003500是哪裡來的?其實就是字元串’15’的十六進制編碼。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

也就是說,二次開發顧問在RFC調用時,将寫死的’15’傳給了接受整型變量的函數參數IV_MAX_ENTRIES. 應該該參數類型為整型,是以’15’的十六進制編碼’31003500’被自動轉換成了對應的整型數3473457. 顯然這不是開發顧問期望的行為,但因為程式能夠繼續運作,是以這個問題暫時被掩蓋了。

而RFC調用完成之後,緊接着是一個嵌套的LOOP. 在Max Hit能按照期望工作的前提下,對于最多包含15條記錄的内表,就算進行嵌套的LOOP操作也能很快完成。但如今因為Max Hit不工作,内表記錄從最多15條一下子變成了超過40萬條,在這麼龐大規模的内表上進行嵌套LOOP操作,性能可想而知。

經曆過這次incident的處理之後,我個人覺得,使用隐式類型轉換的最佳實踐就是根本不去用它。程式員在工作的時候,必須時刻清醒地知道自己在做什麼,要扼住編譯器的咽喉,而不要被編譯器扼住了咽喉。

關于SAP ABAP字元變量和字元串變量字元個數的一個知識點,和一個血案strlen( lv_s2 ) = 1strlen( lv_ss) = 19'15’是怎麼變成魔幻數字3473457的?

感謝閱讀,祝大家五一節快樂。

繼續閱讀