面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊
引入主題,看代碼
我們先來看看以下程序
//編譯器:https://tool.lu/coderunner/
//來源:技術(shù)讓夢(mèng)想更偉大
//作者:李肖遙
#include?
using?namespace?std;
struct?st1?
{
?char?a?;
?int??b?;
?short?c?;
};
struct?st2
{
??short?c?;
??char??a?;
??int???b?;
};
int?main()
{
?cout<<"sizeof(st1)?->?"<?cout<<"sizeof(st2)?->?"<?
?return?0?;
}
編譯的結(jié)果如下:
問題來了,兩個(gè)結(jié)構(gòu)體的內(nèi)容一樣,只是換了個(gè)位置,為什么sizeof(st)
的時(shí)候大小不一樣呢?
沒錯(cuò),這正是因?yàn)閮?nèi)存對(duì)齊的影響,導(dǎo)致的結(jié)果不同。對(duì)于我們大部分程序員來說,都不知道內(nèi)存是怎么分布的。
實(shí)際上因?yàn)檫@是編譯器該干的活,編譯器把程序中的每個(gè)數(shù)據(jù)單元安排在合適的位置上,導(dǎo)致了相同的變量,不同聲明順序的結(jié)構(gòu)體大小的不同。
幾種類型數(shù)據(jù)所占字節(jié)數(shù)
int,long int,short int的寬度和機(jī)器字長(zhǎng)及編譯器有關(guān),但一般都有以下規(guī)則(ANSI/ISO制訂的)
-
sizeof(short int)
<=sizeof(int)
-
sizeof(int)
<=sizeof(long int)
-
short int
至少應(yīng)為16位(2字節(jié)) -
long int
至少應(yīng)為32位
數(shù)據(jù)類型 | 16位編譯器 | 32位編譯器 | 64位編譯器 |
---|---|---|---|
char | 1字節(jié) | 1字節(jié) | 1字節(jié) |
char* | 2字節(jié) | 4字節(jié) | 8字節(jié) |
short int | 2字節(jié) | 2字節(jié) | 2字節(jié) |
int | 2字節(jié) | 4字節(jié) | 4字節(jié) |
unsigned int | 2字節(jié) | 4字節(jié) | 4字節(jié) |
float | 4字節(jié) | 4字節(jié) | 4字節(jié) |
double | 8字節(jié) | 8字節(jié) | 8字節(jié) |
long | 4字節(jié) | 4字節(jié) | 8字節(jié) |
long long | 8字節(jié) | 8字節(jié) | 8字節(jié) |
unsigned long | 4字節(jié) | 4字節(jié) | 8字節(jié) |
什么是對(duì)齊
現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問都可以從任何地址開始,但實(shí)際情況是在訪問特定變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問。
所以這就需要各類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。內(nèi)存對(duì)齊又分為自然對(duì)齊和規(guī)則對(duì)齊。
對(duì)于內(nèi)存對(duì)齊問題,主要存在于struct和union等復(fù)合結(jié)構(gòu)在內(nèi)存中的分布情況,許多實(shí)際的計(jì)算機(jī)系統(tǒng)對(duì)基本類型數(shù)據(jù)在內(nèi)存中存放的位置有限制,它們要求這些數(shù)據(jù)的首地址的值是某個(gè)數(shù)M(通常是4或8);
對(duì)于內(nèi)存對(duì)齊,主要是為了提高程序的性能,數(shù)據(jù)結(jié)構(gòu),特別是棧,應(yīng)盡可能在自然邊界上對(duì)齊,經(jīng)過對(duì)齊后,cpu的內(nèi)存訪問速度大大提升。
自然對(duì)齊
指的是將對(duì)應(yīng)變量類型存入對(duì)應(yīng)地址值的內(nèi)存空間,即數(shù)據(jù)要根據(jù)其數(shù)據(jù)類型存放到以其數(shù)據(jù)類型為倍數(shù)的地址處。
例如char類型占1個(gè)字節(jié)空間,1的倍數(shù)是所有數(shù),因此可以放置在任何允許地址處,而int類型占4個(gè)字節(jié)空間,以4為倍數(shù)的地址就有0,4,8等。編譯器會(huì)優(yōu)先按照自然對(duì)齊進(jìn)行數(shù)據(jù)地址分配。
規(guī)則對(duì)齊
以結(jié)構(gòu)體為例就是在自然對(duì)齊后,編譯器將對(duì)自然對(duì)齊產(chǎn)生的空隙內(nèi)存填充無效數(shù)據(jù),且填充后結(jié)構(gòu)體占內(nèi)存空間為結(jié)構(gòu)體內(nèi)占內(nèi)存空間最大的數(shù)據(jù)類型成員變量的整數(shù)倍。
實(shí)驗(yàn)對(duì)比
首先看這個(gè)結(jié)構(gòu)體
typedef?struct?test_32
{
?char?a;
?short?b;
?short?c;
?char?d;
}test_32;
首先按照自然對(duì)齊,得到如下圖的內(nèi)存分布位置,第一個(gè)格子地址為0,后面遞增。
編譯器將對(duì)空白處進(jìn)行無效數(shù)據(jù)填充,最后將得到此結(jié)構(gòu)體占內(nèi)存空間為8字節(jié),這個(gè)數(shù)值也是最大的數(shù)據(jù)類型short的2個(gè)字節(jié)的整數(shù)倍。
如果稍微調(diào)換一下位置的結(jié)構(gòu)體
typedef?struct?test_32
{
?char?a;
?char?b;
?short?c;
?short?d;
}test_32;
同樣按照自然對(duì)齊如下圖分布
可以看到按照自然對(duì)齊,變量之間沒有出現(xiàn)間隙,所以規(guī)則對(duì)齊也不用進(jìn)行填充,而這里有顏色的方格有6個(gè),也就是6個(gè)字節(jié)
按照規(guī)則對(duì)齊,6字節(jié)是此結(jié)構(gòu)體中最大數(shù)據(jù)類型short的整數(shù)倍,因此此結(jié)構(gòu)體為6字節(jié),后面的空白不需理會(huì),可以實(shí)際編譯一下運(yùn)行,結(jié)果和分析一致為6個(gè)字節(jié)。
double的情況
我們知道32位處理器一次只能處理32位也就是4個(gè)字節(jié)的數(shù)據(jù),而double是8字節(jié)數(shù)據(jù)類型,這要怎么處理呢?
如果是64位處理器,8字節(jié)數(shù)據(jù)可以一次處理完畢,而在32位處理器下,為了也能處理double8字節(jié)數(shù)據(jù),在處理的時(shí)候?qū)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">會(huì)把double拆分成兩個(gè)4字節(jié)數(shù)進(jìn)行處理,從這里就會(huì)出現(xiàn)一種情況如下:
typedef?struct?test_32
{
?char?a;
?char?b;
?double?c;
}test_32;?
這個(gè)結(jié)構(gòu)體在32位下所占內(nèi)存空間為12字節(jié),只能拆分成兩個(gè)4字節(jié)進(jìn)行處理,所以這里規(guī)則對(duì)齊將判定該結(jié)構(gòu)體最大數(shù)據(jù)類型長(zhǎng)度為4字節(jié),因此總長(zhǎng)度為4字節(jié)的整數(shù)倍,也就是12字節(jié)。
這個(gè)結(jié)構(gòu)體在64位環(huán)境下所占內(nèi)存空間為16字節(jié),而64位判定最大為8字節(jié),所以結(jié)果也是8字節(jié)的整數(shù)倍:16字節(jié)。這里的結(jié)構(gòu)體中的double沒有按照自然對(duì)齊放置到理論上的8字節(jié)倍數(shù)地址處,我認(rèn)為這里編譯器也有根據(jù)規(guī)則對(duì)齊做出相應(yīng)的優(yōu)化,節(jié)省了4個(gè)多余字節(jié)。
這部分各位可以按照上述規(guī)則自行分析測(cè)試。
數(shù)組
對(duì)齊值為:min(數(shù)組元素類型,指定對(duì)齊長(zhǎng)度)
。但數(shù)組中的元素是連續(xù)存放,存放時(shí)還是按照數(shù)組實(shí)際的長(zhǎng)度。
如char t[9],對(duì)齊長(zhǎng)度為1,實(shí)際占用連續(xù)的9byte。然后根據(jù)下一個(gè)元素的對(duì)齊長(zhǎng)度決定在下一個(gè)元素之前填補(bǔ)多少byte。
嵌套的結(jié)構(gòu)體
假設(shè)
struct?A
{
??......
??struct?B?b;
??......
};
對(duì)于B結(jié)構(gòu)體在A中的對(duì)齊長(zhǎng)度為:min(B結(jié)構(gòu)體的對(duì)齊長(zhǎng)度,指定的對(duì)齊長(zhǎng)度)
。
B結(jié)構(gòu)體的對(duì)齊長(zhǎng)度為:上述2中結(jié)構(gòu)整體對(duì)齊規(guī)則中的對(duì)齊長(zhǎng)度。舉個(gè)例子
//編譯器:https://tool.lu/coderunner/
//來源:技術(shù)讓夢(mèng)想更偉大
//作者:李肖遙
#include?
#include?
using?namespace?std;
#pragma?pack(8)
struct?Args
{
?char?ch;
?double?d;
?short?st;
?char?rs[9];
?int?i;
}?args;
struct?Argsa
{
??char?ch;
??Args?test;
??char?jd[10];
??int?i;
}arga;
int?main()
{
?cout<<"Args:"<?cout<<""<<(unsigned?long)&args.i-(unsigned?long)&args.rs<?cout<<"Argsa:"<?cout<<"Argsa:"<<(unsigned?long)&arga.i?-(unsigned?long)&arga.jd<?cout<<"Argsa:"<<(unsigned?long)&arga.jd-(unsigned?long)&arga.test<?return?0;
}
輸出結(jié)果:
改成#pragma pack (16)結(jié)果一樣,這個(gè)例子證明了三點(diǎn):
-
對(duì)齊長(zhǎng)度長(zhǎng)于struct中的類型長(zhǎng)度最長(zhǎng)的值時(shí),設(shè)置的對(duì)齊長(zhǎng)度等于無用
-
數(shù)組對(duì)齊的長(zhǎng)度是按照數(shù)組成員類型長(zhǎng)度來比對(duì)的
-
嵌套的結(jié)構(gòu)體中,所包含的結(jié)構(gòu)體的對(duì)齊長(zhǎng)度是結(jié)構(gòu)體的對(duì)齊長(zhǎng)度
指針
主要是因?yàn)?2位和64位機(jī)尋址上,來看看例子
//編譯器:https://tool.lu/coderunner/
//來源:技術(shù)讓夢(mèng)想更偉大
//作者:李肖遙
#include?
#include?
using?namespace?std;
#pragma?pack(4)
struct?Args
{
?int?i;
?double?d;
?char?*p;?
?char?ch;?
?int?*pi;
}args;
int?main()
{????
?cout<<"args?length:"<?cout<<"args1:"<<(unsigned?long)&args.ch-(unsigned?long)&args.p<?cout<<"args2:"<<(unsigned?long)&args.pi-(unsigned?long)&args.ch<?return?0;
}
結(jié)果如下
pack | 4 | 8 |
---|---|---|
length | 32 | 40 |
args1 | 8 | 8 |
args2 | 4 | 8 |
內(nèi)存對(duì)齊的規(guī)則
-
數(shù)據(jù)成員對(duì)齊規(guī)則
結(jié)構(gòu)或聯(lián)合的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack
指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行。
例如struct a里存有struct b,b里有char,int ,double等元素,那b應(yīng)該從8的整數(shù)倍開始存儲(chǔ)。
-
結(jié)構(gòu)體作為成員
如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部"最寬基本類型成員"的整數(shù)倍地址開始存儲(chǔ)。
在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)或聯(lián)合本身也要進(jìn)行對(duì)齊,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)或聯(lián)合最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行。
-
1&2的情況下注意
當(dāng)#pragma pack的n值等于或超過所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)n值的大小將不產(chǎn)生任何效果。
#pragma pack()用法詳解
-
作用
指定結(jié)構(gòu)體、聯(lián)合以及類成員的packing alignment;
-
語(yǔ)法
#pragma pack( [show] | [push | pop] [, identifier], n )
-
說明
-
pack提供數(shù)據(jù)聲明級(jí)別的控制,對(duì)定義不起作用;
-
調(diào)用pack時(shí)不指定參數(shù),n將被設(shè)成默認(rèn)值;
-
一旦改變數(shù)據(jù)類型的alignment,直接效果就是占用memory的減少,但是performance會(huì)下降;
-
語(yǔ)法具體分析
-
show:可選參數(shù)
顯示當(dāng)前packing aligment的字節(jié)數(shù),以warning message的形式被顯示;
-
push:可選參數(shù)
將當(dāng)前指定的packing alignment數(shù)值進(jìn)行壓棧操作,這里的棧是the internal compiler stack,同時(shí)設(shè)置當(dāng)前的packing alignment為n;如果n沒有指定,則將當(dāng)前的packing alignment數(shù)值壓棧;
-
pop:可選參數(shù)
從internal compiler stack中刪除最頂端的record;如果沒有指定n,則當(dāng)前棧頂record即為新的packing alignment數(shù)值;如果指定了n,則n將成為新的packing aligment數(shù)值;如果指定了identifier,則internal compiler stack中的record都將被pop直到identifier被找到,然后pop出identitier,同時(shí)設(shè)置packing alignment數(shù)值為當(dāng)前棧頂?shù)膔ecord;如果指定的identifier并不存在于internal compiler stack,則pop操作被忽略;
-
identifier:可選參數(shù)
當(dāng)同push一起使用時(shí),賦予當(dāng)前被壓入棧中的record一個(gè)名稱;當(dāng)同pop一起使用時(shí),從internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier沒有被找到,則忽略pop操作;
-
n:可選參數(shù)
指定packing的數(shù)值,以字節(jié)為單位;缺省數(shù)值是8,合法的數(shù)值分別是1、2、4、8、16
例子
#include
#include
using?namespace?std;
?
#pragma?pack(4)
struct?m???
{
?int?a;??
?short?b;
?int?c;
};
int?main()
{
?cout?<<"結(jié)構(gòu)體m的大小:"<?cout?<??
??//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?int?offset_b?=?offsetof(struct?m,?a);
?cout?<<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<?system("pause");
?return?0;
}
從運(yùn)行結(jié)果來看我們可以證實(shí)上面內(nèi)存對(duì)齊規(guī)則的第一條:第一個(gè)數(shù)據(jù)成員放在offset為0的地方。
現(xiàn)在咱來看看上面結(jié)構(gòu)體是如何內(nèi)存對(duì)齊的;先用代碼打印它們每個(gè)數(shù)據(jù)成員的存儲(chǔ)地址的偏移量
//編譯器:https://tool.lu/coderunner/
//來源:技術(shù)讓夢(mèng)想更偉大
//作者:李肖遙
#include
#include
using?namespace?std;
?
#pragma?pack(4)
struct?m???
{
?int?a;??
?short?b;
?int?c;
};
int?main()
{
?cout?<<"結(jié)構(gòu)體m的大小:"<?cout?<?int?offset_b?=?offsetof(struct?m,?a);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?int?offset_b1?=?offsetof(struct?m,?b);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?int?offset_b2?=?offsetof(struct?m,?c);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?
?cout?<<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<?cout?<"b相對(duì)于m儲(chǔ)存地址的偏移量:"?<?cout?<"c相對(duì)于m儲(chǔ)存地址的偏移量:"?<?
?//system("pause");
?return?0;
}
在此c在結(jié)構(gòu)體中偏移量為8加上它自身(int)4個(gè)字節(jié),剛好是12(c的開始位置為8,所以要加它的4個(gè)字節(jié))
上面內(nèi)存結(jié)束為11,因?yàn)?-11,12是最大對(duì)齊數(shù)的整數(shù)倍,故取其臨近的倍數(shù),所以就取4的整數(shù)倍即12;
上圖中我用連續(xù)的數(shù)組來模仿內(nèi)存,如圖是它們的內(nèi)存對(duì)齊圖;
如果將最大內(nèi)存對(duì)齊數(shù)改為8,他將驗(yàn)證內(nèi)存對(duì)齊規(guī)則中的第3條。
如果將其改為2,會(huì)發(fā)生什么:我們來看看:
//編譯器:https://tool.lu/coderunner/
//來源:技術(shù)讓夢(mèng)想更偉大
//作者:李肖遙
#include
#include
using?namespace?std;
?
#pragma?pack(2)
struct?m???
{
?int?a;??
?short?b;
?int?c;
};
int?main()
{
?cout?<<"結(jié)構(gòu)體m的大小:"<?cout?<?int?offset_b?=?offsetof(struct?m,?a);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?int?offset_b1?=?offsetof(struct?m,?b);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?int?offset_b2?=?offsetof(struct?m,?c);//?獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量
?
?cout?<<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<?cout?<"b相對(duì)于m儲(chǔ)存地址的偏移量:"?<?cout?<"c相對(duì)于m儲(chǔ)存地址的偏移量:"?<?
?//system("pause");
?return?0;
}
對(duì)于這個(gè)結(jié)果,我們按剛才第一個(gè)例子我所分析的過程來分析這段代碼,得到的是10;
故當(dāng)我們將#pragma pack的n值小于所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,結(jié)果將改變。
對(duì)齊的作用和原因
各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊,可能會(huì)在存取效率上帶來?yè)p失。
比如有些平臺(tái)每次讀都是從偶地址開始,如果一個(gè)int型在32位地址存放在偶地址開始的地方,那么一個(gè)讀周期就可以讀出;
而如果存放在奇地址開始的地方,就可能會(huì)需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該int數(shù)據(jù)。那么在讀取效率上下降很多,這也是空間和時(shí)間的博弈。
CPU每次從內(nèi)存中取出數(shù)據(jù)或者指令時(shí),并非想象中的一個(gè)一個(gè)字節(jié)取出拼接的,而是根據(jù)自己的字長(zhǎng),也就是CPU一次能夠處理的數(shù)據(jù)長(zhǎng)度取出內(nèi)存塊??傊珻PU會(huì)以它“最舒服的”數(shù)據(jù)長(zhǎng)度來讀取內(nèi)存數(shù)據(jù)
舉個(gè)例子
如果有一個(gè)4字節(jié)長(zhǎng)度的指令準(zhǔn)備被讀取進(jìn)CPU處理,就會(huì)有兩種情況出現(xiàn):
-
4個(gè)字節(jié)起始地址剛好就在CPU讀取的地址處,這種情況下,CPU可以一次就把這個(gè)指令讀出,并執(zhí)行,內(nèi)存情況如下
-
而當(dāng)4個(gè)字節(jié)按照如下圖所示分布時(shí)
假設(shè)CPU還在同一個(gè)地址取數(shù)據(jù),則取到第一個(gè)4字節(jié)單元得到了1、2字節(jié)的數(shù)據(jù),但是這個(gè)數(shù)據(jù)不符合需要的數(shù)啊,所以CPU就要在后續(xù)的內(nèi)存中繼續(xù)取值,這才取到后面的4字節(jié)單元得到3、4字節(jié)數(shù)據(jù),從而和前面取到的1、2字節(jié)拼接成一個(gè)完整數(shù)據(jù)。
而本次操作進(jìn)行了兩次內(nèi)存讀取,考慮到CPU做大量的數(shù)據(jù)運(yùn)算和操作,如果遇到這種情況很多的話,將會(huì)嚴(yán)重影響CPU的處理速度。
因此,系統(tǒng)需要進(jìn)行內(nèi)存對(duì)齊,而這項(xiàng)任務(wù)就交給編譯器進(jìn)行相應(yīng)的地址分配和優(yōu)化,編譯器會(huì)根據(jù)提供參數(shù)或者目標(biāo)環(huán)境進(jìn)行相應(yīng)的內(nèi)存對(duì)齊。
什么時(shí)候需要進(jìn)行內(nèi)存對(duì)齊.
一般情況下都不需要對(duì)編譯器進(jìn)行的內(nèi)存對(duì)齊規(guī)則進(jìn)行修改,因?yàn)檫@樣會(huì)降低程序的性能,除非在以下兩種情況下:
-
這個(gè)結(jié)構(gòu)需要直接被寫入文件
-
這個(gè)結(jié)構(gòu)需通過網(wǎng)絡(luò)傳給其他程序
對(duì)齊的實(shí)現(xiàn)
可以通知給編譯器傳遞預(yù)編譯指令,從而改變對(duì)指定數(shù)據(jù)的對(duì)齊方法。
unsigned?int?calc_align(unsigned?int?n,unsigned?align)??
{??
????if?(?n?/?align?*?align?==?n)????????????
????????return?n;??
????return??(n?/?align?+?1)?*?align;??
}?
不過這種算法的效率很低,下面介紹一種高效率的數(shù)據(jù)對(duì)齊算法:
unsigned?int?calc_align(unsigned?int?n,unsigned?align)??
{??????
????return?((n?+?align?-?1)?&?(~(align?-?1)));??
}??
這種算法的原理是:
(align-1)
?:對(duì)齊所需的對(duì)齊位,如:2字節(jié)對(duì)齊為1,4字節(jié)為11,8字節(jié)為111,16字節(jié)為1111...
(&~(align-1))
?:將對(duì)齊位數(shù)據(jù)置位為0,其位為1
(n+(align-1)) & ~(align-1)
:對(duì)齊后的數(shù)據(jù)
總結(jié)
通常,我們寫程序的時(shí)候,不需要考慮對(duì)齊問題,編譯器會(huì)替我們選擇目標(biāo)平臺(tái)的對(duì)齊策略。
但正因?yàn)槲覀儧]注意這個(gè)問題,導(dǎo)致編輯器對(duì)數(shù)據(jù)存放做了對(duì)齊,而我們?nèi)绻涣私獾脑挘蜁?huì)對(duì)一些問題感到迷惑。
所以知其然,更要知其所以然。好了,我們介紹到這里,下一期再見!
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!