3

char に格納された 8 つのブール値の配列を実際に表すオブジェクトを作成しました。ビット単位の演算子と、C で独自のオブジェクトを作成する方法についてさらに学習するために作成しました。2 つの質問があります。

  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. unsigned 型を でチェックしないでください< 0。意味がなく、一部のコンパイラで警告が発生します。
  2. サイズを指定せずに符号なしタイプを使用しないでください ( unsigned intunsigned charなど)。
  3. なぜflag == 0に設定しているの0ですか?
  4. *a で aを抽象化するのは好きではありませんが、決して間違っtypedefているわけではありません。
  5. memset()1 バイトを に設定するために呼び出す必要はありません0
  6. ビットオフセットを計算するために使用powするのはクレイジーです。<<and演算子をチェックして、>>代わりにそれらを使用してください
  7. ステートメントの条件を完全に括弧ifで囲むか、将来のデバッグの苦痛に備えてください。
  8. 関数内で算術andの代わりにビット演算子 and を使用する場合、&これらの複雑なステートメントは必要ありません。|+-SetBitAtIndexif
  9. あなたのGetBitAtIndexルーチンは境界チェックをしていませんindex

そのリストから、あなたのプログラムがすべての場合に動作しないことを意味するのは #9 だけだと思います。徹底的にテストしたわけではありません。これは一見しただけのチェックです。

于 2010-08-07T22:44:50.667 に答える
4

pow(2,index)これは、ビット マスクを作成する最も効率の悪い方法の 1 つです。アッカーマン関数を使用するとさらに悪化する可能性があると想像できますが、pow()かなり遅い側にあります。(1<<index)代わりに使用する必要があります。また、値のビットを設定/クリアするCの方法は異なって見えます。これに関する最近の質問は次のとおりです。


効率的かつ移植可能な方法で C のビットを変更したい場合は、「ビット」について何らかの形で言及した場合にここにいる誰もが提案するビットいじりのページを実際に見る必要があります。


次のコード シーケンス:

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

return (result != 0);return resultまたはreturn !!result(結果を 0 または 1 に強制する必要がある場合)として記述できます。意図を明確にすることは常に良い考えですが、ほとんどの C プログラマーは「結果結果;」を好むでしょう。Cでは、これが意図を明確にする方法だからです。「元の開発者はJavaの男で、ビットについてあまり知らない」などの警告ステッカーのように、ifは不確かに見えます。


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; することもできますが、データのサイズを考えると、これらを一度に 1 つずつヒープに割り当てるのはまったくの狂気です。型の消費者にインラインで宣言させ、アクセサーを使用させます。

さらに...本当にそうしますcharか? それをint.

于 2010-08-07T22:56:09.960 に答える
1

カール・ノーラムのポイントに加えて:

  1. 必要な場合 (つまり、多くのビット値を格納する場合) を除いて、char でスペースを節約しないでください。ビット単位の操作などを実行する必要があるため、はるかに遅くなります。
  2. ほとんどのアーキテクチャでは、char を malloc することでメモリを浪費します。1 つのポインターは、ほとんどの最新のアーキテクチャーで char の 4 から 8 倍かかり、さらに、malloc されたチャンクに関するデータを持っています。
  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ライセンスの下で自発的に公開したもので、一部の権利のみが留保されています。さらに、あなたは私たちにコードを読んで修正してほしいので、すべての権利を留保しても意味がありません.

(追伸.とにかく、制限付きのライセンスの下で些細な作品を公開することはお勧めしません - それは専門的に見えませ- あなたがそうするのに法的な問題がない限り)

これは、自分でリリースしない限り、C で失われないオブジェクトを作成するための適切な実装です。

ごめん?

于 2010-08-07T23:02:51.293 に答える