【问题标题】:Bit-wise left shifting a value into a dynamically allocated memory pointed by void*将值按位左移到 void* 指向的动态分配内存中
【发布时间】:2021-11-03 20:21:54
【问题描述】:

我正在尝试为 Libvirt API 函数创建 CPU-Map。这个想法取决于物理 CPU 的数量,我分配 1、2 或 4 个字节的内存(最多支持 32 个 CPU)。例如,如果一个平台有 16 个 CPU,我分配 2 个字节。

内存分配后,我需要设置CPU位。例如:如果我在平台中有 16 个 CPU,并且我想将一个虚拟 CPU 固定到第 16 个 CPU,我需要在分配的内存中设置 MSB。见下面的代码sn-p。

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

感谢任何帮助。

【问题讨论】:

  • 转换malloc 的结果不会改变它被取消引用时发生的情况,C 不是动态类型的。当你知道你要使用什么类型时,你需要做作业。
  • pCpuscpu_number 嗯...相同或不同的东西?
  • pCpus equal 12 --> case 1 嗯……这真的是你想要的吗?

标签: c void-pointers libvirt


【解决方案1】:

您最好总是使用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);

【讨论】:

  • 肯定是一个更好的解决方案......即使 OP 应该坚持 cpuMap 是一个空指针,它也可以使用
  • 我看不出有任何理由 malloc
【解决方案2】:

你不能尊重void*,因为它是一个不完整的类型,无法通过设计完成。必须将其转换为适当的类型并分配正确的值。

例如:

case 2:
    size = sizeof(unsigned short int);
    cpuMap = malloc(size);
    *(unsigned short int*)cpuMap = 0x1 << cpu_number;
    break;

为其他情况添加类似的代码。

请注意,设置cpuMap 后,只能通过用于初始化它的类型访问(+ 少数例外)以避免违反严格的别名规则。

【讨论】:

    【解决方案3】:

    分配 1 或 2 个字节是没有意义的。始终分配 4 个字节。分配更少不会为您节省任何内存,反而会使代码无缘无故地复杂化。

    另外,对 4 字节内存使用动态内存分配没有(或非常、非常少)意义。您存储其引用的指针在 64 位机器上将是两倍大小:)

    要确定该类型有多少位,请使用标准

    中的固定大小整数
    uint32_t cpumap = 0;
    
    /* ... */
    
    cpumap |= 0x1UL << cpu_number;
    

    【讨论】:

    • 我同意 OP 的方法相当奇怪,但这并不能回答 OP 的要求
    • @4386427 IMO 他只是想多了,他的方法没有意义,所以我提出了一个更合乎逻辑的解决方案
    【解决方案4】:

    使用void * 会破坏类型安全。最好使用单一类型(例如)uint8_t -- 根据 CPU 数量使用 uint8_t/uint16_t/uint32_t 在速度方面几乎没有优势,并且会使代码更复杂。

    我们必须将 CPU 的数量四舍五入才能得到字节数。

    没有必要使用malloc。只需使用基于最大可能 CPU 的固定大小(例如 32、64、128、256)。对于 32 个 CPU 的 [最大] 用例,始终使用 4 个字节对于向量的大小来说并不是真正的问题。


    当我做位向量时,我更喜欢使用宏/函数来隔离操作。

    以下是我过去使用过的一些宏:

    // 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);
    }
    

    【讨论】:

      【解决方案5】:

      libvirt API 提供了旨在与固定 API 一起使用的宏,以简化此操作:

      unsigned char *cpuMap = malloc(VIR_CPU_MAPLEN(pCpus));
      VIR_USE_CPU(cpuMap, cpu_number);
      

      【讨论】:

        猜你喜欢
        • 2012-08-27
        • 1970-01-01
        • 2018-03-03
        • 2017-12-30
        • 1970-01-01
        • 2015-06-19
        • 1970-01-01
        • 2021-04-15
        • 2014-05-13
        相关资源
        最近更新 更多