[英]Write values of different data types in sequence in memory? or, Array with multiple data types?
我對使用C語言寫書比較陌生。我已經使用在網上和印刷版中發現的資源自學了自己。 這是我在C編程中的第一個實際項目。 一定喜歡在職培訓。
我正在用C編寫一些在德州儀器C6701數字信號處理器上使用的代碼。 具體來說,我正在編寫一組通信功能以通過串行端口進行接口。
我參與的項目已有一個用於通過串行端口發送數據的數據包協議。 這是通過將指針移交給要傳輸的數據及其長度(以字節為單位)來進行的。 我要做的就是將要寫入的字節寫入內存中的“數組”中(發送器將字節序列復制到緩沖區中並進行發送)。
我的問題與如何最好地格式化要傳輸的數據有關,我必須發送的數據由幾種不同的數據類型(無符號字符,無符號整數,浮點數等)組成。 我無法將所有內容擴展到float(或int),因為我的通信帶寬受到限制,並且需要使數據包盡可能小。
我本來想用數組格式化數據,
unsigned char* dataTx[10];
dataTx[0]=char1;
dataTx[1]=char2;
etc...
除非我的所有數據都不是char,有些不是unsigned int或unsigned short,這將起作用。
為了處理short和int,我使用了移位(現在讓我們忽略little-endian與big-endian)。
unsigned char* dataTx[10];
dataTx[0]=short1>>8;
dataTx[1]=short1;
dataTx[2]=int1>>24;
dataTx[3]=int1>>16;
etc...
但是,我相信另一種(更好的方法)是使用指針和指針算術。
unsigned char* dataTx[10]
*(dataTx+0) = int1;
*(dataTx+4) = short1;
*(dataTx+6) = char1;
etc...
我的問題 ( 最后 )是,哪種方法(移位或指針算術)是更可接受的方法? 另外,運行起來更快嗎? (我也有運行時約束)。
我的要求:數據要順序存儲在內存中,沒有間隙,中斷或填充。
我對結構還不了解,還不知道結構是否可以作為解決方案。 具體來說,我不知道結構是否總是按順序分配內存位置並且沒有中斷。 我讀到一些東西,表明它們分配了8個字節的塊,並可能引入了填充字節。
現在,我傾向於使用指針方法。 感謝您閱讀這篇長篇文章。
您可能要使用聯合數組。
解決問題的最簡單,最傳統的方法是設置要發送的數據,然后將指向數據的指針傳遞給傳輸例程。 最常見的示例是POSIX send()
例程:
ssize_t send(int socket, const void *buffer, size_t length, int flags);
對於您的情況,可以簡化為:
ssize_t send(const void *buffer, size_t length);
然后使用類似:
send(&int1, sizeof int1);
send(&short1, sizeof short1);
發送出去。 針對您的情況的示例(但很幼稚)實現可能是:
ssize_t send(const void *buffer, size_t length)
{
size_t i;
unsigned char *data = buffer;
for (i = 0; i < length; i++)
{
dataTx[i] = data[i];
}
}
換句話說,使用自動轉換為void *
,然后返回到char *
以按字節方式訪問您的數據,然后將其適當地發送出去。
長的問題,我將嘗試較短的答案。
不要繼續*(dataTx + 4)= short1; 等等,因為這種方法可能會失敗,因為大多數芯片可能只在某些對齊的位置上進行讀/寫操作。 您可以按16位訪問以2對齊的位置,而以32位訪問以4對齊的位置,但是舉一個例子:“ int32 char8 int32”-第二個int32的位置為(dataTx + 5)-不是4字節對齊,您可能會收到“總線錯誤”或類似的信息(取決於您將使用的CPU)。 希望你理解這個問題。
第一種方法-如果您聲明:
struct
{
char a;
int b;
char c;
short d;
};
您現在不再麻煩了,因為編譯器本身會注意結構對齊。 當然,請閱讀有關編譯器中與對齊方式相關的選項的信息(如果是gcc,則簡稱為對齊方式),因為可能存在一個設置,該設置會強制某些結構域進行對齊或對結構域進行打包。 GCC甚至可以定義每個結構的對齊方式(更多內容請參見 )。
另一種方法是使用一些“類似緩沖區的方法”-類似於卡爾·諾魯姆的回答(我不會重復該回答),但是還考慮了在復制更多數據時使用memcpy()調用(例如long long或string),因為這可能比逐字節復制要快。
通常,您將使用移位方法,因為許多芯片不允許您將4字節整數復制到奇數字節地址(或更准確地說,是從奇數字節地址開始的4字節集合中) )。 這稱為對齊。 如果可移植性是一個問題,或者您的DSP不允許未對齊的訪問,則需要進行移位。 如果您的DSP因未對齊訪問而導致嚴重的性能下降,則您可能會為此擔心。
但是,我不會寫出帶有代碼的代碼來對不同類型的代碼進行長期修改,如圖所示。 我希望使用函數(可能是內聯函數)或宏來處理數據的序列化和反序列化。 例如:
unsigned char dataTx[1024];
unsigned char *dst = dataTx;
dst += st_int2(short1, dst);
dst += st_int4(int1, dst);
dst += st_char(str, len, dst);
...
以函數形式,這些函數可能是:
size_t st_int2(uint16_t value, unsigned char *dst)
{
*dst++ = (value >> 8) & 0xFF;
*dst = value & 0xFF;
return 2;
}
size_t st_int4(uint32_t value, unsigned char *dst)
{
*dst++ = (value >> 24) & 0xFF;
*dst++ = (value >> 16) & 0xFF;
*dst++ = (value >> 8) & 0xFF;
*dst = value & 0xFF;
return 4;
}
size_t st_char(unsigned char *str, size_t len, unsigned char *dst)
{
memmove(dst, str, len);
return len;
}
當然,這些功能使代碼變得無聊。 另一方面,它們也減少了出錯的機會。 您可以決定名稱應為st_uint2()
而不是st_int2()
,並且實際上,您可以決定長度應為字節(如此處)還是位(如參數類型)。 只要您始終如一且無聊,就可以做。 您也可以將這些功能組合成更大的功能,以打包整個數據結構。
對於現代編譯器,可能不需要屏蔽操作( & 0xFF
)。 很久很久以前,我似乎記得它們對於避免某些平台上的某些編譯器偶爾出現問題是必要的(因此,我的代碼可以追溯到1980年代,其中包括這種屏蔽操作)。 所說的平台可能已經安息了,所以就我而言,它們仍然在那里仍然是純粹的偏執狂。
請注意,這些函數以big-endian順序傳遞數據。 這些函數可以在大端和小端機器上“按原樣”使用,並且兩種類型的數據都可以正確解釋,因此,使用此代碼,您可以使各種硬件通過網絡進行通信,並且沒有溝通不暢。 如果您要傳遞浮點值,則必須多擔心導線上的表示形式。 盡管如此,您可能應該以平台無關的格式傳輸數據,以使芯片類型之間的互操作盡可能簡單。 (這也是為什么我在類型大小中使用數字的原因;特別是'int'和'long'在不同的平台上可能意味着不同的意思,但是4字節有符號整數仍然是4字節有符號整數,即使您使用不幸-或幸運-足以擁有一台8字節整數的機器。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.