保证C中(void *)数组中的确切数据宽度

时间:2013-01-26 00:34:46

标签: c arrays types

我在C中有一个简单的函数,它提供了一个指向数据数组的void*指针。我知道这个内存块中每个单独数据点的大小(以字节为单位),并且需要保证我可以修改该块中的每个数据点,而不会意外地改变相邻的数据点。在这个例子中,我想将每个值减1。

所有数据点都是8位,16位或32位。

例如:

void myFunction(void* data, size_t arraySize, size_t widthPerDataPoint)
{
  if(!data)
    return -1;
  size_t w = widthPerDataPoint;
  int numPoints = arraySize / widthPerDataPoint;
  int i;
  for(i=0; i<numPoints; i++)
  {
    if(w==1)       // 8 bit
      (*((int8_t*)data + i))--;
    else if(w==2)  // 16 bit
      (*((int16_t*)data + i))--;
    else if(w==4)  // 32 bit
      (*((int32_t*)data + i))--;
  }
}

不幸的是,根据C99规范,int8_t等数据类型仅保证其最小大小,而不是精确大小。有没有办法重新建立和修改数据,并保证我不会粉碎我的阵列或触摸相邻的数据点?此外,是否有一种等效技术可以用于其他数据宽度(即:24位,60位等)?

4 个答案:

答案 0 :(得分:2)

根据定义,通过 n 递增T*类型的指针会将其移位n * sizeof(T)个字节。因此,编译器会保证一致性。不用担心。

答案 1 :(得分:2)

int8_t保证恰好是8位,如果CHAR_BIT==1,则恰好为1个字节。

引用最新C标准的N1570草案,第7.20.1.1节:

  

typedef名称 int N _t 指定有符号整数类型   宽度 N ,无填充位和二进制补码   表示。因此, int8_t 表示这种有符号整数类型   宽度恰好为8位。

虽然为了您的目的,使用uint8_tuint16_t等可能更有意义。

如果实现不支持具有所需特征的类型,则不会定义它们;您可以通过检查来检测到这一点,例如:

#include <stdint.h>
#ifdef UINT8_MAX
/* uint8_t exists */
#else
/* uint8_t doesn't exist */
#endif

(如果CHAR_BIT != 8,则不会定义int8_tuint8_t。)

标准仅保证最小尺寸的[u]intleast_N_t[u]intfast_t类型。

您必须保证阵列及其中的偏移量与您用于访问它的类型正确对齐。我认为你已经在照顾它了。

答案 2 :(得分:1)

代码似乎并非完全不合理。我个人可能会这样做:

 switch(widthPerDataPoint)
 {
    case 1:
       {
          int8_t *dptr = data;
          for(i = 0; i < numPoints; i++)
             dptr[i]--;
       }
       break;
    case 2:
       {
          int16_t *dptr = data;
          for(i = 0; i < numPoints; i++)
             dptr[i]--;
       }
       break;

    case 4:
       {
          int32_t *dptr = data;
          for(i = 0; i < numPoints; i++)
             dptr[i]--;
       }
       break;

    default:
       fprintf(stderr, "Someone gave the wrong width - width=%d\n", 
               widthPerDatapoint);
       break;
}

这里的优点是你不会在每个循环中得到一堆条件。编译器可能会对其进行排序,但我并不总是相信编译器能够解决这些问题 - 我认为它也有点清晰。

答案 3 :(得分:-1)

以下情况如何?

  1. 将值复制到任何大小的本地int

  2. 对局部变量执行递减

  3. 使用适当的位掩码将阵列中的位置清零 (例如,8位的~0xFF)

  4. '和'将局部变量返回到数组中。