1. 程式人生 > >C++的可以執行和跨平臺開發

C++的可以執行和跨平臺開發

概述

  今天聊聊C++的可移植性問題。如果你平時使用C++進行開發,並且你對C++的可移植性問題不是非常清楚,那麼我建議你看看這個系列。即使你目前沒有跨平臺開發的需要,瞭解可移植性方面的知識對你還是很有幫助的。

C++的可移植性這個話題很大,包括了編譯器、作業系統、硬體體系等很多方面,每一個方面都有很多內容。鑑於本人能力、精力都有限,只能介紹每一個方面最容易碰到的問題,供大夥兒參考。

  後面我會分別從編譯器、C++語法、作業系統、第三方庫、輔助工具、開發流程等方面進行介紹。

編譯器

  在跨平臺的開發過程中,很多問題都和編譯器有關。因此我們先來聊聊編譯器相關的問題。

編譯器的選擇

  首先,

GCC是優先要考慮支援的,因為幾乎所有作業系統平臺都有GCC可用。它基本上成了一個通用的編譯器了。如果你的程式碼在A平臺的GCC能夠編譯通過,之後拿到B平臺用類似版本的GCC編譯,一般也不會有太大問題。因此GCC是肯定要考慮支援的。

  其次,要考慮是否支援本地編譯器。所謂本地編譯器就是作業系統廠商自產的編譯器。例如:相對於Windows的本地編譯器就是Visual C++。相對於Solaris的本地編譯器就是SUNCC。如果你對效能比較敏感或者想用到某些本地編譯器的高階功能,可能就得考慮在支援GCC的同時也支援本地編譯器。

編譯警告

編譯器是程式設計師的朋友,很多潛在的問題(包括可移植性),編譯器都是可以發現並給出警告的,如果你平時注意這些警告資訊,可以減少很多麻煩。因此我強烈建議:

1把編譯器的警告級別調高;

2不要輕易忽略編譯器的警告資訊。

交叉編譯器

  交叉編譯器的定義參見“維基百科”。通俗地說,就是在A平臺上編譯出執行在B平臺上的二進位制程式。假設你要開發的應用是執行在Solaris上,但是你手頭沒有能夠執行SolarisSPARC機器,這時候交叉編譯器就可以派上用場了。一般情況下都使用GCC來製作一個交叉編譯器,限於篇幅,這裡就不深入聊了。有興趣的同學可以參見“這裡”。

異常處理

  上一個帖子“語法”由於篇幅有限,沒來得及聊異常,現在把和異常相關的部分單獨拿出來說一下。

小心new分配記憶體失敗

  早期的老式編譯器生成的程式碼,如果new失敗會返回空指標。我當年用的

Borland C++ 3.1似乎就是這樣的,現在這種編譯器應該不多見了。如果你目前用的編譯器還有這種行為,那你就慘了。你可以考慮過載new操作符來丟擲 bad_alloc異常,便於進行異常處理。

稍微新式一點的編譯器,就不是僅僅返回空指標了。當new操作符發現記憶體告急,按照標準的規定(參見C++ 03標準18.4.2章節),它應該去呼叫new_handler函式(原型為typedef void (*new_handler)();)。標準建議new_handler函式幹如下三件事:

1、設法去多搞點記憶體來;

2、丟擲bad_alloc異常;

3、呼叫abort()或者exit()退出程序。

由於new_handler函式是可以被重新設定的(通過呼叫set_new_handler),所以上述的行為它都可能有。

綜上所述,new分配記憶體失敗,有可能三種可能:

1、返回空指標;

2、丟擲異常;

3、程序立即終止。

如果你希望你的程式碼具有較好的移植性,你就得把這三種情況都考慮到。

慎用異常規格

  異常規格在我看來不是一個好東西,不信可以去看看《C++ Coding Standards - 101 Rules, Guidelines & Best Practices》的第75條。(具體有哪些壞處以後專門開一個C++異常和錯誤處理的帖子來聊)言歸正傳,按照標準(參見03標準18.6.2章節),如果一個函式拋到外面的異常沒有包含在該函式的異常規範中,那麼應該呼叫unexcepted()。但是並非所有編譯器生成的程式碼都遵守標準(比如某些版本的VC編譯器)。如果你的需要支援的編譯器在異常規範上的行為不一致,那就得考慮去掉異常規範宣告。

不要跨模組丟擲異常

  此處說的模組是指動態庫。如果你的程式包含有多個動態庫,不要把異常拋到模組的匯出函式之外。畢竟現在C++還沒有ABI標準(估計將來也未必會有),跨模組丟擲異常會有很多不可預料的行為。

不要使用結構化異常處理(SEH

  如果你從來沒有聽說過SEH,那就當我沒說,跳過這段。如果你以前習慣於用SEH,在你打算寫跨平臺程式碼之前,要改掉這個習慣。包含有SEH的程式碼只能在Windows平臺上編譯通過,肯定無法跨平臺的。

關於catch(...)

照理說,catch(...)語句只能夠捕獲C++的異常型別,對於訪問違例、除零錯等非C++異常是無能為力的。但是某些情況下(比如某些VC編譯器),諸如訪問違例、除零錯也可以被catch(...)捕獲。所以,你如果希望程式碼移植性好,就不能在程式邏輯中依賴上述catch(...)的行為。

硬體體系相關

  這次聊的話題主要是和硬體體系有關的。比如你的程式需要支援不同型別的CPUx86SPARCPowerPC),或者是同種型別不同字長的CPU(比如x86x86-64),這時候你就需要關心一下硬體體系的問題。

基本型別的大小

C++中基本型別的大小(佔用的位元組數)會隨著CPU字長的變化而變化。所以,假如你要表示一個int佔用的位元組數,千萬不要直接寫“4”(順便說一下,直接寫“4”還犯了Magic Number的大忌,詳見這裡),而應該寫“sizeof(int)”;反過來,如果你要定義一個大小必須為4位元組的有符號整數,也不要直接用int,要用預先typedef好的定長型別(比如boost庫的int32_tACE庫的ACE_INT32、等)。

  差點忘了,指標的大小也有上述的問題,也要小心。

位元組序

  如果你沒聽說過“位元組序”這玩意兒,請看“維基百科”。通俗地打個比方,在一個大尾序的機器上有一個4位元組的整數0x01020304,通過網路或者檔案傳到一臺小尾序的機器上就會變成0x04030201;據說還有一種中尾序的機器(不過我沒接觸過),上述整數會變成0x02010403

  如果你編寫的應用程式中涉及網路通訊,一定要在記得進行主機序和網路序的翻譯;如果涉及跨機器傳輸二進位制檔案,也要記得進行類似的轉換。

記憶體對齊

  如果你不曉得“記憶體對齊”是什麼東東,請看“維基百科”。簡單來說,出於CPU處理上的效能考慮,結構體中的資料不是緊挨著的,而是要空開一些間隔。這樣的話,結構體中每個資料的地址正好都是某個字長的整數倍。

  由於C++標準中沒有定義記憶體對齊的細節,因此,你的程式碼也不能依賴對齊的細節。凡是計算結構體大小的地方,都老老實實寫上sizeof()

  有些編譯器支援#pragma pack預處理語句(可以用來修改對齊字長),不過這種語法不是所有編譯器都支援,要慎用。

移位操作

  對於有符號整數的右移操作,有些系統預設使用算數右移(最高的符號位不變),有些預設使用邏輯右移(最高的符號位補0)。所以,不要對有符號整數進行右移操作。順便說一下,即使沒有移植性問題,程式碼中也儘量少用移位運算子。那些企圖用移位運算來提高效能的同學更要注意了,這麼幹不但可讀性很差,而且吃力不討好。只要不太弱智的編譯器,都會自動幫你搞定這種優化,無須程式設計師操心。

作業系統

  上一個帖子提到了“硬體體系”相關的話題,今天來說說和作業系統相關的話題。C++跨平臺開發中和OS相關的瑣事挺多,所以今天會囉嗦比較長的篇幅,請列位看官見諒 :-)

  為了不繞口,以下把Linux和各種Unix統稱為Posix系統。

檔案系統(FileSystem以下簡稱FS

  剛開始搞跨平臺開發的新手,多半都會碰上和FS相關的問題。所以先來聊一下FS。歸納下來,開發中容易碰上的FS差異主要有如下幾個:目錄分隔符的差異;大小寫敏感的差異;路徑中禁用字元的差異。

  為了應對上述差異,你要注意如下幾點:

1、檔案和目錄命名要規範

  在給檔案和目錄命名時,儘量只使用字母和數字。不要在同一個目錄下放兩個名稱相似(名稱中只有大小寫不同,例如foo.cppFoo.cpp)的檔案。不要使用某些OS的保留字(例如auxconnulprn)作檔名或目錄名。

  補充一下,剛才說的命名,包括了原始碼檔案、二進位制檔案和執行時建立的其它檔案。

2#include語句要規範

  當你寫#include語句時,要注意使用正斜線“/”(比較通用)而不要使用反斜線“/”(僅在Windows可用)。#include語句中的檔案和目錄名要和實際名稱保持大小寫完全一致。

3、程式碼中涉及FS操作,儘量使用現成的庫

  已經有很多成熟的、用於FS的第三方庫(比如boost::filesystem)。如果你的程式碼涉及到FS的操作(比如目錄遍歷),儘量使用這些第三方庫,可以幫你省不少事情。

文字檔案的回車CR/換行LF

  由於幾個知名的作業系統對回車/換行的處理不一致,導致了這個煩人的問題。目前的局面是:Windows同時使用CRLFLinux和大部分的Unix使用LF;蘋果的Mac系列使用CR

  對於原始碼管理,好在很多版本管理軟體(比如CVSSVN)都會智慧地處理這個問題,讓你從程式碼庫取回本地的原始碼能適應本地的格式。

  如果你的程式需要在執行時處理文字檔案,要留意本文方式開啟和二進位制方式開啟的區別。另外,如果涉及跨不同系統傳輸文字檔案,要考慮進行適當的處理。

  ★檔案搜尋路徑(包括搜尋可執行檔案和動態庫)

  在Windows下,如果要執行檔案或者載入動態庫,一般會搜尋當前目錄;而Posix系統則不盡然。所以如果你的應用涉及到啟動程序或載入動態庫,就要小心這個差異。

  ★環境變數

  對於上述提到的搜尋路徑問題,有些同學想通過修改PATHLD_LIBRARY_PATH來引入當前路徑。假如使用這種方法,建議你只修改程序級的環境變數,不要修改系統級的環境變數(修改系統級有可能影響到同機的其它軟體,產生副作用)。

  ★動態庫

  如果你的應用程式使用動態庫,強烈建議動態庫匯出標準C風格的函式(儘量不要匯出類)。如果在Posix系統中載入動態庫,切記慎用RTLD_GLOBAL標誌位。這個標誌位會Enable全域性符號表,有可能會導致多個動態庫之間的符號名衝突(一旦碰到這種事,會出現匪夷所思的執行時錯誤,極難除錯)。

  ★服務/看守程序

  如果你不清楚服務和看守程序的概念,請看維基百科(這裡和這裡)。為了敘述方便,以下統稱服務。

  由於C++開發的模組大部分是後臺模組,經常會碰到服務的問題。編寫服務需要呼叫好幾個系統相關的API,導致了與作業系統的緊密耦合,很難用一套程式碼搞定。因此比較好的辦法是抽象出一個通用的服務外殼,然後把業務邏輯程式碼作為動態庫掛載到它下面。這樣的話,至少保證了業務邏輯的程式碼只需要一套;服務外殼的程式碼雖然需要兩套(一個用於Windows、一個用於Posix),但他們是業務無關的,可以很方便地重用。

  ★預設棧大小

  不同的作業系統,棧的預設大小差別很大,從幾十KB(據說Symbian只有12K,真摳門)到幾MB不等。因此你事先要打聽一下目標系統的預設棧大小,如果碰上像Symbian這樣摳門的,可以考慮用編譯器選項調大。當然,養成“不在棧上定義大陣列/大物件”的好習慣也很重要,否則再大的棧也會被撐爆的。

多執行緒

  最近一個多月寫的帖子比較雜,導致本系列又好久沒更新了。結果又有網友在評論中催我了,搞得我有點囧。今天趕緊把多執行緒篇補上。上次聊作業系統的時候,由於和OS有關的話題比較瑣碎,雜七雜八說了一大堆。當時一看篇幅有點長,就把多程序和多執行緒的部分給留到後面了。

  ★編譯器

關於C執行庫選項

  先來說一個很基本的問題:關於C執行庫(後面簡稱CRTC Run-Time)的設定。本來不想聊這麼低階的問題,但周圍有好幾個人都在這個地方吃過虧,所以還是講一下。

  大部分C++編譯器都會自帶有CRT(可能還不止一個)。某些編譯器自帶的CRT可能會根據執行緒的支援分為單執行緒CRT和多執行緒CRT兩類。當你要進行多執行緒開發的時候,別忘了確保相關的C++工程專案使用的是多執行緒的CRT。否則會死得很難看。

  尤其當你使用Visual C++建立工程專案,更加要小心。如果新建的工程專案是不含MFC的(包括Console工程和Win32工程),那工程的預設設定會是使用“單執行緒CRT”,如下圖所示:

關於優化選項

  “優化選項”是另一個很關鍵的編譯器相關話題。有些編譯器提供號稱很牛X的優化選項,但是某些優化選項可能會有潛在的風險。編譯器可能自作主張打亂執行指令的順序,從而導致出乎意料的執行緒競態問題(Race Condition,詳細解釋看“這裡”)。劉未鵬同學在“C++多執行緒記憶體模型”裡舉了幾個典型的例子,大夥兒可以去瞧一瞧。

  建議只使用編譯器常規的速度優化選項即可。其它那些花哨的優化選項,增加的效果未必明顯,但是潛在的風險不小。實在不值得冒險。

  以GCC為例:建議用-O2 選項即可(其實-O2 是一堆選項的集合),沒必要冒險用-O3 (除非你有很充足的理由)。除了-O2 -O3 之外,GCC還有一大坨(估計有上百個)其它的優化選項。如果你企圖用當中的某個選項,一定要先把它的特性、可能的副作用都摸清楚,否則將來死都不知道怎麼死的。

  ★執行緒庫的選擇

  由於當前的C++ 03標準幾乎沒有涉及執行緒相關的內容(即使將來C++ 0x包含了執行緒的標準庫,編譯器廠商的支援在短期內也未必全面),所以在未來很長的一段時間,跨平臺的多執行緒支援還是要依賴第三方庫。所以執行緒庫的選擇是大大滴重要。下面大致介紹一下幾個知名的跨平臺執行緒庫。

  ◇ACE

  先說一下ACE這個歷史悠久的庫。如果你之前從未接觸過它,先看“這裡”掃盲。從ACE的全稱(Adaptive Communication Environment)來看,它應該是以“通訊”為主業。不過ACE對“多執行緒”這個副業的支援還是非常全面的,比如互斥鎖(ACE_Mutex)、條件變數(ACE_Condition)、訊號量(ACE_Semaphore)、柵欄(ACE_Barrier)、原子操作(ACE_Atomic_Op)等等。對某些型別比如ACE_Mutex還細分為執行緒讀寫鎖(ACE_RW_Thread_Mutex)、執行緒遞迴鎖(ACE_Recursive_Thread_Mutex)等等。

  除了支援很全面,ACE還有另一個很明顯的優點,就是對各種作業系統平臺及其自帶的編譯器支援很好。包括一些老式的編譯器(比如VC6),它也能夠支援(此處所說的支援,不光是能編譯通過,而且要能穩定執行)。這個優點對於跨平臺開發那是相當相當滴明顯。

  那缺點捏?由於ACE開工的年頭很早(大概是上世紀九十年代中期),那會兒很多C++的老特性都還沒出來(更別提新特性了),所以感覺ACE整個的風格比較老氣,遠不如boost那麼時髦前衛。

  ◇boost::thread

boost::thread正好和ACE形成鮮明對照。這玩意貌似從boost 1.32版本開始引入,年頭比ACE短。不過得益於boost裡一幫大牛的支援,發展還是蠻快的。到目前的boost 1.38版本,也能夠支援許多特性了(不過似乎沒ACE多)。鑑於很多C++標準委員會的成員雲集在boost社群中,隨著時間的推移,boost::thread終將成為C++執行緒的明日之星,前途無量啊!

boost::thread的缺點就是支援的編譯器不夠多,尤其是一些老式編譯器(很多boost的子庫都有此問題,多半因為用了一些高階的模板語法)。這對於跨平臺而言一個比較明顯的問題。

  ◇wxWidgets QT

wxWidgetsQT都是GUI介面庫,但是它們也都內建和對執行緒的支援。wxWidgets執行緒的簡介可以看“這裡”,關於QT執行緒的簡介可以看“這裡”。這兩個庫對執行緒的支援差不多,都提供了諸如mutexconditionsemaphore等常用的機制。不過特性沒有ACE豐富。

  ◇如何權衡

  對於開發GUI軟體並已經用上了wxWidgets或者QT,那你可以直接用它們內建的執行緒庫(前提是你只用到基本的執行緒功能)。由於它們內建的執行緒庫,特性稍嫌單薄。萬一你需要某高階的執行緒功能,那得考慮替換成boost::threadACE

  至於boost::threadACE的取捨,主要得看軟體的需求了。如果你要支援的平臺挺多挺雜,那建議選用ACE,以免碰上編譯器不支援的問題。如果你只需要支援少數幾個主流的平臺(比如WindowsLinuxMac),那建議用boost::thread。畢竟主流作業系統上的編譯器,對boost的支援還是蠻好的。

  ★程式設計上的注意事項

  其實多執行緒開發,需要注意的地方挺多的,我只能大致列幾個印象比較深的注意事項。

  ◇關於

相關推薦

C++的可以執行跨平臺開發

概述   今天聊聊C++的可移植性問題。如果你平時使用C++進行開發,並且你對C++的可移植性問題不是非常清楚,那麼我建議你看看這個系列。即使你目前沒有跨平臺開發的需要,瞭解可移植性方面的知識對你還是很有幫助的。 C++的可移植性這個話題很大,包括了編譯器、作業系統、硬體體

C++的可移植性跨平臺開發

file volatil rec 遍歷 程序包 arc scu 千萬 之前 概述   今天聊聊C++的可移植性問題。如果你平時使用C++進行開發,並且你對C++的可移植性問題不是非常清楚,那麽我建議你看看這個系列。即使你目前沒有跨平臺開發的需要,了解可移植性方面的知識對你還

開源物聯網框架ServerSuperIO 3.0正式釋出(C#),跨平臺:Win&Win10 Iot&Ubuntu&Ubuntu Mate,一套裝置驅動跨平臺掛載,附:開發套件教程。

3.0版本主要更新內容: 1.增加跨平臺能力:Win&Win10 Iot&Ubuntu&Ubuntu Mate 2.統一裝置驅動介面:可以一套裝置驅動,跨平臺掛載執行,降低人力成本,提高開發效率。 3.增加二次開發套件:支援控制檯和UI介面兩種方式。 4.增加配置工具:

Ubuntu下用gladeGTK+開發C語言界面程序(一)

命令行 簡單的 暑假 all 位置 相同 write 3.0 面向對象的思想 前言:對於大學中計算機系的每年暑假的課設有太多想說的,能從中學到非常多東西,當然不排除打醬油的,這些能夠掠過哦,凡事都打醬油。人生也是打醬油的吧。2333。 對於大三曾經的課設一般的要求

Unity 5實戰 使用C#Unity開發多平臺遊戲pdf

name clas position ati 下載地址 組件 inspector ins over 下載地址:城通網盤 作者簡介編輯 Joseph Hocking是一位交互式媒體開發方面的軟件工程師。他就職於Synapse Games公司並在芝加哥哥倫比亞學院教授遊戲開發

C程序的執行當前進程的結束

結束進程 csharp log 取消 main函數 sha atexit 註冊 歷程 內核使程序執行的唯一方法,就是調用exec函數,這個函數又會啟動一個C程序啟動例程,這個啟動例程是C程序的啟動地址。負責調用main函數,並接受mainn函數的返回值。 使得進程結束的

C# Inventor二次開發—002—啟動Inventor及零部件創建打開

pan clas manage cat nts tor AR .get -s 一、啟動Inventor   Inventor.Application對象是基於COM開發Inventor的出發點,以下是我封裝獲取Inventor Application方法: 1

C++-類動態內存分配 大發彩_票平臺開發

lin 原型 def 顯示 指向 自己的 clu 增加 sse 大發彩_票平臺開發 地址一:【hubawl.com】狐霸源碼論壇地址二:【bbscherry.com】 類和動態內存分配 動態內存和類 C++在分配內存時是讓程序在運行時決定內存分配,而不是在編譯時決定。

Win7下C/C++跨平臺開發工具IDE的安裝之Eclipse-CDT

span nbsp 開發環境 download ges win back .org lan 2. win7下安裝Eclipse-CDT運行C/C++程序: 下載Eclipse-CDT 64位:http://www.eclipse.org/downloads/packages

打通C/4HANAS/4HANA的一個原型開發:智能服務創新案例

信息 支付 abc 喜歡 ron 選擇 weave com 博客 今年6月SAP發布C/4HANA之後,有顧問朋友們在微信公眾號後臺留言,詢問C/4HANA如何同SAP的數字化核心S/4HANA系統結合起來,從而打通企業的前後端業務,幫助企業實現數字化轉型。 有的顧問朋友

C#執行緒系列講座(1):BeginInvokeEndInvoke方法

開發語言:C#3.0 IDE:Visual Studio 2008 本系列教程主要包括如下內容:1.  BeginInvoke和EndInvoke方法 2.  Thread類 3. 執行緒池 4. 執行緒同步基礎 5. 死鎖 6. 執行

打通C/4HANAS/4HANA的一個原型開發:智慧服務創新案例

今年6月SAP釋出C/4HANA之後,有顧問朋友們在微信公眾號後臺留言,詢問C/4HANA如何同SAP的數字化核心S/4HANA系統結合起來,從而打通企業的前後端業務,幫助企業實現數字化轉型。 有的顧問朋友們詢問有沒有具體的案例來體現這種前後端一體化的解決方案,正好SAP成都研究院Customer Ex

[轉]CC++執行時庫

轉自csdn原文:https://blog.csdn.net/ithzhang/article/details/20160009 圖片請去原文檢視 在使用VC構建專案時,經常會遇到下面的連結錯誤:   初學者面對這些錯誤常常不知所錯:libcmt.lib是什麼東西?msvcrtd.dll又是幹嗎用的?在

Ubuntu命令列執行C程式C++程式

首先Ctrl + T 開啟一個終端,cd到你建立C/C++檔案的目錄下。 下面以建立 helloc.c 和 hellocpp.cpp 進行演示 vim helloc.c 按 i 進入插入操作,然後寫C程式碼: #include<stdio.h> int

c++ 使用wxWidgets進行跨平臺開發

本文闡述了wxWidgets的由來,以及從wxWidgets的特點出發,說明了選擇wxWidgets給我們帶來的好處,並且通過一個典型的例子討論瞭如何在C++中使用wxWidgets開發跨平臺的軟體。 什麼是wxWidgets? wxWidgets是一個跨平臺的軟體開發包。它誕生於1992年

C++遊戲開發那些事,告訴你怎麼用C++縱橫遊戲程式設計!

C語言和C++ C 語言可以說是一門設計的非常成功的語言。但是C語言沒有OOP的特性,在做一些大型專案的時候力不從心。一些大型的C專案,隨著專案的臃腫,人類基本沒辦 法維護這個專案了。要維護這麼龐大的專案而又不出錯,只能加入一些OOP特性重構,有經驗的C程式設計師寫著寫著,很多概念就類似C+

執行緒設計(linux c pthread_mutex_trylockpthread_mutex_lock)

1.問題:理想情況下有兩條執行緒,一條執行緒不斷插入佇列,一條執行緒不斷取出佇列,兩條執行緒是併發執行的,但實驗階段的現象卻是第一條執行緒全部插入佇列後第二條執行緒才會開始取 (1)執行緒一: pt

白話跨平臺C++執行緒池實現

執行緒池在一個C++專案中是必不可少的。去看任何一個C++開發框架,絕大部分都會實現一個執行緒池。而如今C++11已經成熟,藉助C++標準庫中的執行緒庫std::thread,以及標準庫提供的多執行緒同步神器std::condition_variable(這個已

常用的C/C++框架庫、開發資源

– 1. Webbench Webbench是一個在Linux下使用的非常簡單的網站壓測工具。它使用fork()模擬多個客戶端同時訪問我們設定的URL,測試網站在壓力下工作的效能,最多可以模擬3萬個併發連線去測試網站的負載能力。Webbench使用C語言編寫, 程式碼實在太簡潔,原始碼加起來不到600

一些SAP Partners能夠通過二次開發實現打通C/4HANAS/4HANA的方法介紹

有好幾位朋友在公眾號後臺給我留言詢問SAP C/4HANA和S/4HANA整合的方案。 儘管我給這些朋友推送了一個方案:打通C/4HANA和S/4HANA的一個原型開發:智慧服務創新案例,然而我得到的反饋是:在這個創新案例裡,需要在C/4HANA裡的服務雲做一些後臺開發,即下圖紅色方框標註