3

我创建了一个对象,它实际上表示存储在 char 中的 8 个布尔值数组。我做了更多关于按位运算符和在 C 中创建自己的对象的知识。所以我有两个问题:

  1. 我可以确定以下代码是否始终有效吗?
  2. 这是一个很好的实现来制作一个不会在 C 中丢失的对象,除非你自己释放它。

编码:

/*
 *  IEFBooleanArray.h
 *  IEFBooleanArray
 *
 *  Created by ief2 on 8/08/10.
 *  Copyright 2010 ief2. All rights reserved.
 *
 */

#ifndef IEFBOOLEANARRAY_H
#define IEFBOOLEANARRAY_H

#include <stdlib.h>
#include <string.h>
#include <math.h>

typedef char * IEFBooleanArrayRef;

void IEFBooleanArrayCreate(IEFBooleanArrayRef *ref);
void IEFBooleanArrayRelease(IEFBooleanArrayRef ref);
int IEFBooleanArraySetBitAtIndex(IEFBooleanArrayRef ref, 
                                 unsigned index, 
                                 int flag);
int IEFBooleanArrayGetBitAtIndex(IEFBooleanArrayRef ref, 
                                 unsigned index);

#endif

/*
 *  IEFBooleanArray.c
 *  IEFBooleanArray
 *
 *  Created by ief2 on 8/08/10.
 *  Copyright 2010 ief2. All rights reserved.
 *
 */

#include "IEFBooleanArray.h"

void IEFBooleanArrayCreate(IEFBooleanArrayRef *ref) {
    IEFBooleanArrayRef newReference;

    newReference = malloc(sizeof(char));
    memset(newReference, 0, sizeof(char));
    *ref = newReference;
}

void IEFBooleanArrayRelease(IEFBooleanArrayRef ref) {
    free(ref);
}

int IEFBooleanArraySetBitAtIndex(IEFBooleanArrayRef ref, unsigned index, int flag) {
    int orignalStatus;

    if(index < 0 || index > 7)
        return -1;

    if(flag == 0)
        flag = 0;
    else
        flag = 1;

    orignalStatus = IEFBooleanArrayGetBitAtIndex(ref, index);
    if(orignalStatus == 0 && flag == 1)
        *ref = *ref + (int)pow(2, index);
    else if(orignalStatus == 1 && flag == 0)
        *ref = *ref - (int)pow(2, index);

    return 0;
}

int IEFBooleanArrayGetBitAtIndex(IEFBooleanArrayRef ref, unsigned index) {
    int result;
    int value;

    value = (int)pow(2, index);
    result = value & *ref;

    if(result == 0)
        return 0;
    else
        return 1;
}

我更像是一个 Objective-C 的人,但我真的想更多地学习 C。任何人都可以要求更多我可以提高自己的“家庭作业”吗?

谢谢,ief2

4

5 回答 5

10
  1. 不要用 来检查无符号类型< 0,它没有意义,并且会在某些编译器上引起警告。
  2. 不要使用未指定大小的无符号类型(unsigned int,unsigned char等)。
  3. 如果flag == 0你为什么将它设置为0
  4. 我不喜欢*在 a 中抽象出 away typedef,但这无论如何都没有
  5. 您无需调用memset()即可将单个字节设置为0.
  6. 使用pow计算位偏移是疯狂的。查看<<and>>运算符并改用它们
  7. 将您的语句条件完全括if起来,或为将来调试痛苦做好准备。
  8. 如果您在函数中使用位运算符&|不是算术+和,则无论如何您都不需要所有这些复杂的语句。-SetBitAtIndexif
  9. 你的GetBitAtIndex例程没有边界检查index

我认为,从该列表中,#9 是唯一意味着您的程序无法在所有情况下工作的选项。我没有对它进行详尽的测试——这只是初步检查。

于 2010-08-07T22:44:50.667 回答
4

pow(2,index)是产生位掩码的效率较低的方法之一。我可以想象使用 Ackermann 函数可能会更糟,但pow()速度很慢。你应该(1<<index)改用。此外,在值中设置/清除位的 C'ish 方式看起来不同。这是最近的一个问题:


如果你想以一种高效且可移植的方式在 C 中处理位,那么你真的应该看看 bit twiddling 页面,如果你以某种方式提到“位”,这里的每个人都会向你建议:


以下代码序列:

if(result == 0)
        return 0;
    else
        return 1;

可以写成return (result != 0);,return resultreturn !!result(如果结果应该被强制为 0 或 1) 。尽管明确意图总是一个好主意,但大多数 C 程序员会更喜欢“结果”;因为在 C 中,这种方式可以使您的意图清晰。if 看起来很可疑,就像一个警告标签,上面写着“原始开发人员是一个 Java 人,对比特知之甚少”之类的。


newReference = malloc(sizeof(char));
memset(newReference, 0, sizeof(char));

malloc + memset(x,0,z) == calloc();


您有一种方法可以报告错误(无效索引),IEFBooleanArraySetBitAtIndex不能报告IEFBooleanArrayGetBitAtIndex. 这是不一致的。使错误报告统一,否则您的库的用户将错误检查。

于 2010-08-07T22:50:33.247 回答
3

至于访问 char 对象中的 #n 位,您可以使用移位和屏蔽,而不是使用 pow() 函数:

设置位#n:

a = a | (1 << n);

清除位 #n:

a = a & (~(1 << n));

获取位#n:

return ((a >> n) & 1);
于 2010-08-07T22:46:23.277 回答
1

似乎没有人提到这一点(我很惊讶),但是......你不能告诉我你是认真做的malloc(sizeof(char))吗?这是一个非常小的分配。使它成为堆分配的对象是没有意义的。只需将其声明为char.

如果你想有某种程度的封装,你可以这样做:typedef char IEFBoolArray;并制作访问器函数来操作IEFBoolArray. 甚至可以做typedef struct { char value; } IEFBoolArray; 但是考虑到数据的大小,在堆上一次分配这些数据将是非常疯狂的。让该类型的消费者只需将其声明为内联并使用访问器。

进一步......你确定你想要它char吗?如果将其提升为更大的代码,例如int.

于 2010-08-07T22:56:09.960 回答
1

除了卡尔诺鲁姆点:

  1. 不要以这种方式在 char 中节省空间,除非你必须这样做(即你存储了很多位值)。它要慢得多,因为您必须执行按位运算等。
  2. 在大多数架构上,您通过分配字符来浪费内存。在大多数现代架构上,一个指针的占用量是 char 的 4 到 8 倍,此外,您还拥有有关 malloced 块的数据。
  3. 可能静态大小不是最好的方法,因为它不灵活。我看不到为它使用特殊功能的任何好处。

从第 3 点开始,类似:

typedef struct {
    uint64_t size;
    uint64_t *array;
}bitarray;

bitarray bitarray_new(uint64_t size) {
    bitarray arr;
    arr.size = size;
    arr.array = calloc(size/8);
    return arr;
}

void bitarray_free(bitarray arr) {
    free(arr.array);
}

void bitarray_set(bitarray arr, uint64_t index, int bit) {
  assert (index <= arr.size)
  if (bit)
    array[index/8] |= 1 << (index % 8);
  else
    array[index/8] ^= ~(1 << (index % 8));
}

void bitarray_get(bitarray arr, uint64_t index, int bit) {
  assert (index <= arr.size)
  return array[index/8] & 1 << (index % 8);
}

Copyright 2010 ief2. All rights reserved.

实际上他们不是。您自愿在cc-by-sa许可下发布它们,仅保留部分权利。此外,您希望我们阅读和修改代码,因此保留所有权利是没有意义的。

(PS。无论如何,我建议不要在限制性许可下发布琐碎的作品——它看起来并不专业——除非你有法律问题要这样做)

这是一个很好的实现来制作一个不会在 C 中丢失的对象,除非你自己释放它。

对不起?

于 2010-08-07T23:02:51.293 回答