1. 程式人生 > >C++不允許使用不完整的型別說明

C++不允許使用不完整的型別說明

在講述柔性陣列成員之前,首先要介紹一下不完整型別(incomplete type)。不完整型別是這樣一種型別,它缺乏足夠的資訊例如長度去描述一個完整的物件。

incomplete types (types that describe objects but lack information needed to determine their sizes).

C與C++關於不完整型別的語義是一樣的。

基本上沒有什麼書介紹過不完整型別,很多人初次遇到這個概念時腦袋會一片空白。事實上我們在實際的工程設計中經常使用不完整型別,只不過不知道有這麼個概念而已。前向宣告就是一種常用的不完整型別:

class base;

struct test;

base和test只給出了宣告,沒有給出定義。不完整型別必須通過某種方式補充完整,才能使用它們進行例項化,否則只能用於定義指標或引用,因為此時例項化的是指標或引用本身,不是base或test物件。

一個未知長度的陣列也屬於不完整型別:

extern int a[];

extern不能去掉,因為陣列的長度未知,不能作為定義出現。不完整型別的陣列可以通過幾種方式補充完整才能使用,大括號形式的初始化就是其中一種方式:

int a[] = { 10, 20 };

柔性陣列成員(flexible array member)也叫伸縮性陣列成員,它的出現反映了C程式設計師對精煉程式碼的極致追求。這種程式碼結構產生於對動態結構體的需求。在日常的程式設計中,有時候需要在結構體中存放一個長度動態的字串,一般的做法,是在結構體中定義一個指標成員,這個指標成員指向該字串所在的動態記憶體空間,例如:

struct test{

       int a;

       double b;

       char *p;

};

 p指向字串。這種方法造成字串與結構體是分離的,不利於操作,如果把字串跟結構體直接連在一起,不是更好嗎?於是,可以把程式碼修改為這樣:

char a[] = “hello world”;

struct test *PntTest = ( struct test* )malloc( sizeof( struct test ) + strlen( a ) + 1 );

strcpy( PntTest + 1, a );

這樣一來,( char* )( PntTest + 1 )就是字串“hello world”的地址了。這時候p成了多餘的東西,可以去掉。但是,又產生了另外一個問題:老是使用( char* )( PntTest + 1 )不方便。如果能夠找出一種方法,既能直接引用該字串,又不佔用結構體的空間,就完美了,符合這種條件的程式碼結構應該是一個非物件的符號地址,在結構體的尾部放置一個0長度的陣列是一個絕妙的解決方案。不過,C/C++標準規定不能定義長度為0的陣列,因此,有些編譯器就把0長度的陣列成員作為自己的非標準擴充套件,例如:

struct test

{

       int a;

       double b;

       char c[0];

};

c就叫柔性陣列成員,如果把PntTest指向的動態分配記憶體看作一個整體,c就是一個長度可以動態變化的結構體成員,柔性一詞來源於此。c的長度為0,因此它不佔用test的空間,同時PntTest->c就是“hello world”的首地址,不需要再使用( char* )( PntTest + 1 )這麼醜陋的語法了。

鑑於這種程式碼結構所產生的重要作用,C99甚至把它收入了標準中:

6.7.2.1 Structure and union specifiers

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.

C99使用不完整型別實現柔性陣列成員,標準形式是這樣的: 

struct test

{     int a;

       double b;

       char c[];

};

c同樣不佔用test的空間,只作為一個符號地址存在,而且必須是結構體的最後一個成員。柔性陣列成員不僅可以用於字元陣列,還可以是元素為其它型別的陣列,例如:

struct test

{

       int a;

       double b;

       float c[];

};

應當儘量使用標準形式,在非C99的場合,可以使用指標方法。有些人使用char a[1],這是非常不可取的,把這樣的a用作柔性陣列成員會發生越界行為,雖然C/C++標準並沒有規定編譯器應當檢查越界,但也沒有規定不能檢查越界,為了一個小小的指標空間而犧牲移植性,是不值得的。

相關推薦

C++中為什麼允許通過返回型別過載函式的辯論

2004-07-05 13:25:31 別逗了問個問題:1。C++中為什麼不允許通過返回型別過載函式?2。為什麼不允許通過返回型別解析模板函式? 2004-07-05 14:47:55 完美廢人返回型別是一種可有可無的東西…… 2004-07-05 16:41:23 完美

C++允許使用完整型別說明

在講述柔性陣列成員之前,首先要介紹一下不完整型別(incomplete type)。不完整型別是這樣一種型別,它缺乏足夠的資訊例如長度去描述一個完整的物件。 incomplete types (types that describe objects but lack i

C++允許使用完整型別說明

在講述柔性陣列成員之前,首先要介紹一下不完整型別(incomplete type)。不完整型別是這樣一種型別,它缺乏足夠的資訊例如長度去描述一個完整的物件。incomplete types (types that describe objects but lack information needed to

C++報錯允許使用完整型別

#include "pch.h" #include <iostream> #include <fstream>//報錯是因為沒有新增相應的標頭檔案的原因 using namesp

5.C#2.0之完整型別(完成)

  5.1不完整型別宣告      新型別修飾符partial,用於在多個部分定義同一個型別。為了確保與現存程式的相容性,這個修飾符和其他修飾符不同,它不是一個關鍵字,且它必須緊鄰在關鍵字class、struct、interface之前。   &nbs

CC++關於完整型別的說明

在講述柔性陣列成員之前,首先要介紹一下不完整型別(incomplete type)。不完整型別是這樣一種型別,它缺乏足夠的資訊例如長度去描述一個完整的物件。 6.2.5 Types incomplete types (types that describe objects

c#securityexception允許所請求的註冊表訪問權

registry dex content filename except user set key 解決 【轉載】 c#securityexception不允許所請求的註冊表訪問權 開機自啟動程序如下:

C#部分方法能有返回型別

C#部分方法又叫分部方法。部分方法在一個部分類中定義(沒有方法體),在另一個部分類中實現。兩個部分類中,都要使用partial關鍵詞。 部分方法可以是靜態的,但總是私有的,且不能有返回值。使用

C#複習_使用第三個變數交換兩個int型別變數的值

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace _05不使用temp變數int型別資料交換 { class Progra

C#中找型別或名稱空間名稱"SqlConnection"以及連線別的資料庫的名稱空間

可能原因一:在空間引用時,沒有寫using System.Data.SqlClient; 可能原因二:在空間引用中已經寫了using System.Data.SqlClient;這行程式碼,但是還是出現此錯誤,因為沒有引入這個名稱空間。 解決辦法:右擊專案名,找到“新增引用...”,找到System.Dat

C++ 的巢狀類模板的特化定義允許寫在類定義的範圍內

最近在使用在使用模板特化寫一段程式時發現一個奇怪的問題,比如像如下程式碼: #include <iostream>using namespace std;class CMyClass{public: template <typename T> struct test { 

[筆記]c++包含純虛擬函式的類允許被例項化

class CalcTax{ public: virtual void calc_tax()=0; // 純虛擬函式 }; class SalesOrder{ private: Cal

C#實現窗體拖動、允許窗體拖動、任意控制元件執行時拖動

1、不允許窗體被拖動。即使點選藍色標題條。        程式碼片段,加入不想被拖動的窗體中即可         protectedoverridevoid WndProc(refMessage m)         {             base.WndProc(ref m);           

C# Dictionary在foreach中允許修改值

在 foreach 中修改Dictionary中的值是不允許的,可以將key 先放在List中,foreach 這個list ,找到需要修改的項後,再修改原Dic中的內容。 例如 Dictionary<string, int> imgSet = new Dictionar

C++中的函式過載中為什麼考慮返回值型別

1. 問題描述 函式過載是指在同一作用域內,可以有一組具有相同函式名,不同引數列表的函式,這組函式被稱為過載函式。那為什麼不可以是函式名相同,引數列表相同,函式的返回值不同呢? 2. 從一個函式過載例項說起           看下面的一個例子,來體會一下:實現一個列印

C++可變長確定型別的引數

#include "stdafx.h" #include <cstdarg> #include <string.h> #include "iostream" using namespace std; typedef struct Params

關於C++中輸入與變數型別匹配的解決辦法

        在C++控制檯程式中,常常需要用cin輸入某個型別的變數,但是因為客戶可能輸入與變數型別不相符的情況。此時需要在處理資料前判斷輸入是否正確,不正確的時候重新輸入。         簡單的處理過程如下所示: #include <iostream>

C++ 關於“允許使用資料成員初始值設定”的問題

這應該算是C++11新標準的一個重大的改動了!建議使用VS2015使用新標準! C++11 之前的標準是不允許在類內初始化非靜態資料成員的,只有靜態常量整型資料成員,才可以在類中初始化。具體原因可以

c++中為什麼允許虛建構函式?

剛才試了一下,c++確實不允許虛構造函式。測試程式碼:class A { public:         virtual A()        {                cout<<"sgsfsdfasf";        }private:      

為什麼很多公司允許使用C++ STL?

最初開始禁用 C++ STL,更多地是早期專案編碼實踐中留下的慣例,被後來的程式設計師繼承下來。老專案中這種選擇尤其地多。不過如果有人將其上升到公司行為在不同專案中全面禁用 STL,則沒有必要,而且我傾向於做這種決定的人並不理解 C++ 編譯系統。一般來說,專案中禁用 C++ 多見於兩種具體場景:或者專案的產