按位左移一个值到由 void* 指向的动态分配的内存中
Bit-wise left shifting a value into a dynamically allocated memory pointed by void*
我正在尝试为 Libvirt API 函数创建一个 CPU-Map。这个想法是根据物理CPUs的数量,我分配1、2或4字节的内存(最多支持32 CPUs)。比如一个平台有16个CPUs,我分配2个字节。
分配内存后,我需要设置 CPU 位。例如:如果我平台有16个CPU,我想给第16个CPUpin一个VirtualCPU,我需要在分配的内存中设置MSB。请参阅下面的代码片段。
void *cpuMap;
switch (pCpus/8) {
case 0:
case 1:
size = sizeof(unsigned char);
cpuMap = (unsigned char*) malloc(size);
break;
case 2:
size = sizeof(unsigned short int);
cpuMap = (unsigned short int*) malloc(size);
break;
case 3:
case 4:
default:
size = sizeof(unsigned int);
cpuMap = (unsigned int*) malloc(size);
break;
}
*cpuMap = 0x1 << cpu_number; //error: invalid use of void expression
我在编译过程中遇到以下错误
vcpu_scheduler.c:317:3: warning: dereferencing ‘void *’ pointer
317 | *cpuMap = 0x1 << cpu_number;
| ^~~~~~~
vcpu_scheduler.c:317:11: error: invalid use of void expression
317 | *cpuMap = 0x1 << cpu_number;
| ^
make: *** [Makefile:4: compile] Error 1
感谢任何帮助。
您不能引用 void*
,因为它是一个不完整的类型,无法通过设计完成。必须将其转换为适当的类型并分配正确的值。
例如:
case 2:
size = sizeof(unsigned short int);
cpuMap = malloc(size);
*(unsigned short int*)cpuMap = 0x1 << cpu_number;
break;
为其他情况添加类似代码。
请注意,设置后 cpuMap
只能由用于初始化它的类型访问(+ 少数例外)以避免违反严格的别名规则。
您最好总是使用 unsigned char
(或 uint8_t
),并在需要多个字节时分配多个字节(和索引):
unsigned char *cpuMap;
cpuMap = malloc((pCpus + 7U)/8U); // round up to a mulitple of 8
memset(cpuMap, 0, (pCpus + 7U)/8U);
cpuMap[cpu_number / 8U] |= 1U << (cpu_number % 8U);
分配 1 或 2 个字节没有意义。始终分配 4 个字节。分配更少的内存不会为您节省任何内存,反而会使代码无缘无故地复杂化。
对 4 字节内存使用动态内存分配也没有(或非常非常小)意义。您存储其引用的指针在 64 位机器上的大小将是两倍 :)
要确定类型有多少位,请使用来自标准
的固定大小的整数
uint32_t cpumap = 0;
/* ... */
cpumap |= 0x1UL << cpu_number;
使用void *
会破坏类型安全。最好使用单一类型(例如)uint8_t
——根据 CPU 数量使用 uint8_t/uint16_t/uint32_t
在速度方面几乎没有优势,并使代码更复杂。
我们必须对 CPU 数进行四舍五入以获得字节数。
没有真正需要使用 malloc
。只需使用基于最大可能 CPU 的固定大小(例如 32、64、128、256)。对于 32 个 CPU 的[最大]用例,始终使用四个字节并不是向量大小的真正问题。
当我做位向量时,我更喜欢使用macros/functions来隔离操作。
以下是我过去使用过的一些宏:
// btv.h -- bit vector primitives
// NOTE: by using 0x80, we are compatible with perl's vec function
typedef unsigned char btv_t;
// number of bytes for vector
#define BTVSIZE(_bit) \
(((_bit) + 7) >> 3)
// index/offset into bit vector
#define BTVOFF(_bit) \
((_bit) >> 3)
// bit vector bit mask
#define BTVMSK(_bit) \
(0x80 >> ((_bit) >> 3))
// bit vector byte pointer
#define BTVPTR(_sym,_bit) \
(((btv_t *) _sym) + BTVOFF(_bit))
// set bit in vector
#define BTVSET(_sym,_bit) \
*BTVPTR(_sym,_bit) |= BTVMSK(_bit)
// clear bit in vector
#define BTVCLR(_sym,_bit) \
*BTVPTR(_sym,_bit) &= ~BTVMSK(_bit)
// test bit in vector
#define BTVTST(_sym,_bit) \
(*BTVPTR(_sym,_bit) & BTVMSK(_bit))
// set/clear bit in vector
#define BTVFLG(_sym,_bit,_set) \
do { \
btv_t *__btvptr__ = BTVPTR(_sym,_bit); \
btv_t __btvmsk__ = BTVMSK(_bit); \
if (_set) \
*__btvptr__ |= __btvmsk__; \
else \
*__btvptr__ &= ~__btvmsk__; \
} while (0)
这是用于 cpus 的函数包装器:
// cpumap.c -- CPU mask primitives
#include "btv.h"
// pick whatever maximum number of CPUs you want ...
#define CPUMAX 256
typedef btv_t cpumap_t[BTVSIZE(CPUMAX)];
void
cpumapset(cpumap_t map,unsigned int cpuno)
{
BTVSET(map,cpuno);
}
void
cpumapclr(cpumap_t map,unsigned int cpuno)
{
BTVCLR(map,cpuno);
}
btv_t
cpumaptst(cpumap_t map,unsigned int cpuno)
{
return BTVTST(map,cpuno);
}
libvirt API 提供了旨在与固定 API 一起使用的宏,以简化此操作:
unsigned char *cpuMap = malloc(VIR_CPU_MAPLEN(pCpus));
VIR_USE_CPU(cpuMap, cpu_number);
我正在尝试为 Libvirt API 函数创建一个 CPU-Map。这个想法是根据物理CPUs的数量,我分配1、2或4字节的内存(最多支持32 CPUs)。比如一个平台有16个CPUs,我分配2个字节。
分配内存后,我需要设置 CPU 位。例如:如果我平台有16个CPU,我想给第16个CPUpin一个VirtualCPU,我需要在分配的内存中设置MSB。请参阅下面的代码片段。
void *cpuMap;
switch (pCpus/8) {
case 0:
case 1:
size = sizeof(unsigned char);
cpuMap = (unsigned char*) malloc(size);
break;
case 2:
size = sizeof(unsigned short int);
cpuMap = (unsigned short int*) malloc(size);
break;
case 3:
case 4:
default:
size = sizeof(unsigned int);
cpuMap = (unsigned int*) malloc(size);
break;
}
*cpuMap = 0x1 << cpu_number; //error: invalid use of void expression
我在编译过程中遇到以下错误
vcpu_scheduler.c:317:3: warning: dereferencing ‘void *’ pointer
317 | *cpuMap = 0x1 << cpu_number;
| ^~~~~~~
vcpu_scheduler.c:317:11: error: invalid use of void expression
317 | *cpuMap = 0x1 << cpu_number;
| ^
make: *** [Makefile:4: compile] Error 1
感谢任何帮助。
您不能引用 void*
,因为它是一个不完整的类型,无法通过设计完成。必须将其转换为适当的类型并分配正确的值。
例如:
case 2:
size = sizeof(unsigned short int);
cpuMap = malloc(size);
*(unsigned short int*)cpuMap = 0x1 << cpu_number;
break;
为其他情况添加类似代码。
请注意,设置后 cpuMap
只能由用于初始化它的类型访问(+ 少数例外)以避免违反严格的别名规则。
您最好总是使用 unsigned char
(或 uint8_t
),并在需要多个字节时分配多个字节(和索引):
unsigned char *cpuMap;
cpuMap = malloc((pCpus + 7U)/8U); // round up to a mulitple of 8
memset(cpuMap, 0, (pCpus + 7U)/8U);
cpuMap[cpu_number / 8U] |= 1U << (cpu_number % 8U);
分配 1 或 2 个字节没有意义。始终分配 4 个字节。分配更少的内存不会为您节省任何内存,反而会使代码无缘无故地复杂化。
对 4 字节内存使用动态内存分配也没有(或非常非常小)意义。您存储其引用的指针在 64 位机器上的大小将是两倍 :)
要确定类型有多少位,请使用来自标准
的固定大小的整数uint32_t cpumap = 0;
/* ... */
cpumap |= 0x1UL << cpu_number;
使用void *
会破坏类型安全。最好使用单一类型(例如)uint8_t
——根据 CPU 数量使用 uint8_t/uint16_t/uint32_t
在速度方面几乎没有优势,并使代码更复杂。
我们必须对 CPU 数进行四舍五入以获得字节数。
没有真正需要使用 malloc
。只需使用基于最大可能 CPU 的固定大小(例如 32、64、128、256)。对于 32 个 CPU 的[最大]用例,始终使用四个字节并不是向量大小的真正问题。
当我做位向量时,我更喜欢使用macros/functions来隔离操作。
以下是我过去使用过的一些宏:
// btv.h -- bit vector primitives
// NOTE: by using 0x80, we are compatible with perl's vec function
typedef unsigned char btv_t;
// number of bytes for vector
#define BTVSIZE(_bit) \
(((_bit) + 7) >> 3)
// index/offset into bit vector
#define BTVOFF(_bit) \
((_bit) >> 3)
// bit vector bit mask
#define BTVMSK(_bit) \
(0x80 >> ((_bit) >> 3))
// bit vector byte pointer
#define BTVPTR(_sym,_bit) \
(((btv_t *) _sym) + BTVOFF(_bit))
// set bit in vector
#define BTVSET(_sym,_bit) \
*BTVPTR(_sym,_bit) |= BTVMSK(_bit)
// clear bit in vector
#define BTVCLR(_sym,_bit) \
*BTVPTR(_sym,_bit) &= ~BTVMSK(_bit)
// test bit in vector
#define BTVTST(_sym,_bit) \
(*BTVPTR(_sym,_bit) & BTVMSK(_bit))
// set/clear bit in vector
#define BTVFLG(_sym,_bit,_set) \
do { \
btv_t *__btvptr__ = BTVPTR(_sym,_bit); \
btv_t __btvmsk__ = BTVMSK(_bit); \
if (_set) \
*__btvptr__ |= __btvmsk__; \
else \
*__btvptr__ &= ~__btvmsk__; \
} while (0)
这是用于 cpus 的函数包装器:
// cpumap.c -- CPU mask primitives
#include "btv.h"
// pick whatever maximum number of CPUs you want ...
#define CPUMAX 256
typedef btv_t cpumap_t[BTVSIZE(CPUMAX)];
void
cpumapset(cpumap_t map,unsigned int cpuno)
{
BTVSET(map,cpuno);
}
void
cpumapclr(cpumap_t map,unsigned int cpuno)
{
BTVCLR(map,cpuno);
}
btv_t
cpumaptst(cpumap_t map,unsigned int cpuno)
{
return BTVTST(map,cpuno);
}
libvirt API 提供了旨在与固定 API 一起使用的宏,以简化此操作:
unsigned char *cpuMap = malloc(VIR_CPU_MAPLEN(pCpus));
VIR_USE_CPU(cpuMap, cpu_number);