簡體   English   中英

返回給定 C 中的指針的 16 位

[英]Returning 16-bits given a pointer in C

一個塊由一個 64 位長的 integer 表示,它被分成 4 個 16 位的部分。

我需要使用下面的 function 返回一個 16 位部分。

unsigned short get_16bitsection(unsigned long *start, int index) {
// Fill this in 
}

使用強制轉換來實現這一點很誘人,但一個常見的誤解是“一切都只是字節”,因此您可以安全地做到這一點。 一個稱為嚴格別名的規則實際上禁止這樣做。 您的代碼可能看起來可以工作,特別是在較舊和不太復雜的編譯器上,但在重度優化時代,您違反了這樣的語言規則,實際上是在玩火。

相反,您應該將所需的字節復制uint16_t中,然后返回它:

uint16_t get_16bitsection(uint64_t *start, int index) {
  uint16_t result;
  memcpy(&result, (char*)start + index*sizeof(uint16_t), sizeof(uint16_t));
  return result;
}

在這里,我轉換為char*以便我們可以按字節導航您的塊(此別名是通常嚴格別名規則的特別允許的例外),然后應用index*sizeof(uint16_t)的偏移量以達到所需的索引(假設您已指定小端序)。 最后,我們將字節復制到result中,並返回它。

如果您擔心性能,請不要擔心。 您已經將uint16_t從本地 scope 復制到調用 scope 中; 剛才它有了名字。 如果這個 function混疊違規版本慢,那么這證明你已經混淆了優化器走得太遠。

只需使用工會。

long int x=0x123456789abcdef0;

union {
    long int x;
    unsigned short arr[4];
} c;

c.x = x;
printf("%04x %04x %04x %04x\n", c.arr[0], c.arr[1], c.arr[2], c.arr[3]);

結果:

def0 9abc 5678 1234

給定指針返回 16 位
一個塊由一個 64 位長的 integer 表示,它分為 4 個 16 位段

要以獨立於字節序的可移植方式訪問數據並檢索 0:LS 16 位到 3:MS 16 位,請使用>>


由於unsigned long可能只有 32 位,建議使用unsigned long longuint_least64_t
考慮使指針const以允許此 function 用於const數據。

unsigned short get_16bitsection(const unsigned long long *start, int index) {
  #define MASK_16BIT 0xFFFFu
  return MASK_16BIT & (*start >> (16*index));
} 
  • 掩碼在unsigned short不是 16 位的稀有機器上很有用。 IAC,我更喜歡面具而不是演員 - 減少范圍的更溫和的方式。
  • 或者使用強制轉換: (unsigned short)(uint16_t)雖然這稍微不那么可移植,因為uint16_t可能不存在並且unsigned short可能 > 16 位。

也許我在這里錯過了重點,但它可能就像這樣簡單:

unsigned short get_16bitsection_be(unsigned long *start, int index) {
  unsigned short *p = (unsigned short*) start;

  return p[3 - index];
}

unsigned short get_16bitsection_le(unsigned long *start, int index) {
  unsigned short *p = (unsigned short*) start;

  return p[index];
}

大端和小端之間的區別在這里是相關的。

請注意,您應該考慮使用stdint.h為這些類型賦予更有意義的名稱,並明確您實際在做什么:

uint16_t get_16bitsection_le(uint64_t *start, int index) {
  uint16_t *p = (uint16_t*) start;

  return p[index];
}

uint16_t get_16bitsection_be(uint64_t *start, int index) {
  uint16_t *p = (uint16_t*) start;

  return p[3 - index];
}

您的第二種方法走在了正確的軌道上,但是該代碼被許多無關緊要的東西弄得一團糟,再加上沒有意義的* 8偏移量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM