RFC-0045:零大小的空白結構體 | |
---|---|
狀態 | 已遭拒 |
領域 |
|
說明 | RFC-0056 (「空白結構體」) 允許定義空白結構體,從而改善語言人體工學。空白結構體沒有任何內容,但目前佔用 1 個位元組的線路,以便所有 FIDL 語言實作項目相容。這使用不必要的空間,通常會因為 FIDL 在許多情況下的八位元組對齊而變差。 |
作者 | |
提交日期 (年-月-日) | 2018-12-26 |
審查日期 (年-月-日) | 2019-05-29 |
拒絕原因
這個 RFC 已由作者拒絕,因為作業優先順序較高; 影響程度低 之後可以再審視這部分
因此有部分部分不完整。
摘要
RFC-0056 (「Empty Structs」) 改善語言人體工學, 可定義空白結構體。 空白結構體沒有任何內容,但目前佔用 所有 FIDL 語言實作都相容。 這會使用不必要的空間,而且通常因為 FIDL 的 在許多情況下都經過八位元組對齊
此 RFC 以 RFC-0056 為基礎,藉由增強空白結構體以佔用零位元組的方式 好極了!
提振精神
RFC-0056 可列出空白結構的用途:
- 預期日後的用途
- 將選項設為聯集
- 做為「指令」的一部分 圖案、
除了物件中,含有零資訊的物件通常不容易處理, 將電線空間降到零,有效率的執行方式 空白結構對未來潛在 FIDL 作業來說可能很重要,例如 代數資料類型 或「泛型」。
一體大的結構體設計也會使所有其他 FIDL 目標語言 支付 C++ 特有的成本 (詳情請參閱下方的「設計」 詳情)。 其他語言通常可以表示沒有位元組的空白結構體。
設計
兩種設計:單選。我們得先選。
我偏好設計 #1,其中我們使用長度為零的陣列表示空白 結構體 這樣比較不容易讓使用者感到驚訝,而且資料平等且一致 無論用途為何 缺點是我們需要 C 擴充套件,但是我們可能不接受。
第 2 類設計雖可以完成,但若能達到令人驚訝的 空白結構體做為 FIDL 方法的參數。 希望我能針對這個問題提供建議和意見。
如果編譯器支援零長度陣列,我們也假設設計 #1 如果不是,則設計 #2應該是這樣。
設計 #1:零長度陣列
此 RFC 提議使用長度為零的陣列來代表空白的結構。 這是 FIDL 目標支援的常見擴充功能 C 和C++ 編譯器。
一個簡單的例子呈現 C 和C++:
// FIDL: struct Empty {};
// define a zero-length array type
typedef int FIDLEmptyStructInternal[0];
typedef struct {
FIDLEmptyStructInternal reserved;
} Empty;
上述程式碼片段會同時為 C 和sizeof(Empty) == 0
C++。
在實務上,產生的繫結程式碼應關閉各種警告
適用於 C 和 C++1;GitHub Gist 的資料
產生的 C 和C++ 繫結。
設計 #2:省略發射空結構體 (Structs Altoget)
需要 FIDL 結構體才能轉換為 C 和 C++ 中的對等結構。 空白結構體是特殊情況,因為 C 和 C++ 的處理方式不同 空白結構體:
- C 會保留空白結構體的大小未定義2。
許多編譯器 (例如
gcc
和clang
),因此定義空白字元 將結構 大小為零。 - C++ 會定義空白結構的 1。 「空白基地」 類別」最佳化為 部分編譯器在一定程度下 情況。
作為替代方案,RFC-0056 提議產生含有單一結構體的結構體
代表空白結構的 uint8
成員,這在兩個 C 中都保持一致
和 C++
有三種不同的結構定義會顯示空白結構:
- 在包含的結構體內
- 所屬聯集或資料表內
- 視為「頂層」作為 FIDL 介面的參數 方法。
這三種情境可以個別處理。
遏止結構體內部
包含的 struct 中空的結構體可以擁有 省略了空白結構。 舉例來說,以下 FIDL 結構:
// FIDL
struct FooOptions {
// There is currently no information here but
// we have preserved the plumbing for now.
};
struct Foo {
uint32 before;
FooOptions options;
uint32 after;
};
只要省略產生「FooOptions」的空白的 struct 成員 C/C++ 繫結:
// generated C or C++ code
struct Foo {
uint32_t before;
// "FooOptions options" is missing here
uint32_t after;
};
序列化的 FIDL 線格式隨後會與 C/C++ 記憶體相容 且可以直接轉換為/從任一格式投放。
由於空白的 struct 沒有資訊,因此無法存取
.options
會員的影響不大。
如果結構體之後變更為非空白,則包含的結構體可以
發出來源中的先前空白 struct 成員 options
。3
使用者可能會想做的一個合理做法
空白結構體的位址,即 &(foo.options)
,此位址不再
達成這項目標
我們認為,以一致、跨語言的方式權衡利弊
零大小的空白結構體
TODO(apang):Go、Rust、Dart
遏止資料表或聯集內
資料表或 (靜態或可延伸) 聯集具有一般 (「標記」) 指出資料表/聯集包含的資訊。 在這個例子中,有一個空白的結構體「carries information」我們可以理解 雖然空白結構本身就代表資訊的存在 因此不會出現任何資訊
因此,資料表或聯集仍會發出序數,讓用戶端程式碼 以瞭解資料表/聯集中包含哪些資訊。 但是,空白的結構體本身將無法存取。 例如,空白結構體的聯集:
// FIDL
struct Option1 {};
struct Option2 {};
union {
// an "empty" union!
Option1 o1;
Option2 o2;
};
仍會:
- 具備定義明確的記憶體佈局,其中包含
uint32
列舉標記。 - 發出列舉代表運算法和適當存取子方法的列舉 ,以便用戶端程式碼建立及檢查這類聯集。
TODO(apang):加入範例 C/C++ 繫結。
資料表類似:有空白結構做為資料表欄位 所代表的就是資訊 與聯集的做法相同,也就是為序數和 但若省略了空白結構體的存取權 — 這類程式碼仍可用於 表格。
TODO(apang):Go、Rust、Dart
作為 FIDL 方法參數
目前在某些情況下,會使用空白結構做為 FIDL 方法參數 (例如 fuchsia.ui.viewsv1 中):
interface ViewContainerListener {
// |ViewInfo| is an empty struct
OnChildAttached(uint32 child_key, ViewInfo child_view_info) -> ();
};
struct ViewInfo {};
空白結構的任何方法參數可以是:
- 會從方法簽章中省略 (建議),
- 在 C 或 C++ 中,標準化為單一空白的單例模式類型 (例如
fidl::EmptyStruct
) 未直接對應至零位元組線 格式,或 - 直接發出,但語言表示法未直接發出 編碼/解碼作業
變更
- FIDL 來源語言不必變更。
- FIDL 線格式和說明文件會有所變動, 結構體在線路上需要 0 個位元組,而非 1 個位元組。
fidlc
不需要變更。- 所有語言後端 (C、C++、Rust、Go、Dart) 都必須更新為 反映本節所述的繫結變更。 此操作應以硬性轉換的方式完成,這樣跨層 ABI 才能進行 同時保留相容性。
執行策略
實作方式與 RFC-0056 類似。 且必須拆分至多個 CL:
- CL 來更新所有語言產生的繫結,但不會更新 跨語言相容性測試
- 強制轉換整合 CL,確保擲骰子取得成功。
- 更新跨語言。
- 。
無需變更這個 RFC 的 FIDL 來源語言。
缺點、替代方案和未知
請注意,
- 在 C++ 和 C++ 中保持一致
- 這兩種語言的大小導入方式不同
- C++ 理論上需要
- 長度為零的陣列
- C++ [[no_unique_address]]
既有藝術品和參考資料
https://herbsutter.com/2009/09/02/when-is-a-zero-length-array-okay/