3

CLSID 構造体でデータ圧縮を行うように設計されたコードを書いています。それらを 128 ビット整数の圧縮ストリームとして保存しています。ただし、問題のコードは、無効な CLSID をストリームに配置できる必要があります。これを行うために、それらを 1 つの大きな文字列として残しました。ディスク上では、次のようになります。

+--------------------------+-----------------+------------------------+
|                          |                 |                        |
| Length of Invalid String | Invalid String  | Compressed Data Stream |
|                          |                 |                        |
+--------------------------+-----------------+------------------------+

文字列の長さをエンコードするには、文字列の長さである 32 ビット整数を一度に 1 バイトずつ出力する必要があります。これが私の現在のコードです:

std::vector<BYTE> compressedBytes;
DWORD invalidLength = (DWORD) invalidClsids.length();
compressedBytes.push_back((BYTE)  invalidLength        & 0x000000FF);
compressedBytes.push_back((BYTE) (invalidLength >>= 8) & 0x000000FF));
compressedBytes.push_back((BYTE) (invalidLength >>= 8) & 0x000000FF));
compressedBytes.push_back((BYTE) (invalidLength >>= 8));

このコードは頻繁に呼び出されるわけではありませんが、デコード段階で何千回も呼び出される同様の構造が必要になります。これが最も効率的な方法なのか、それとも誰かがより良い方法を思いつくことができるのか、興味がありますか?

皆さんありがとう!

ビリー3

編集:いくつかの回答を調べた後、このミニテストプログラムを作成して、どれが最速かを確認しました:

// temp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <ctime>
#include <iostream>
#include <vector>

void testAssignedShifts();
void testRawShifts();
void testUnion();

int _tmain(int argc, _TCHAR* argv[])
{
    std::clock_t startTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testAssignedShifts();
    }
    std::clock_t assignedShiftsFinishedTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testRawShifts();
    }
    std::clock_t rawShiftsFinishedTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testUnion();
    }
    std::clock_t unionFinishedTime = std::clock();
    std::printf(
        "Execution time for assigned shifts: %08u clocks\n"
        "Execution time for raw shifts:      %08u clocks\n"
        "Execution time for union:           %08u clocks\n\n",
        assignedShiftsFinishedTime - startTime,
        rawShiftsFinishedTime - assignedShiftsFinishedTime,
        unionFinishedTime - rawShiftsFinishedTime);
    startTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testAssignedShifts();
    }
    assignedShiftsFinishedTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testRawShifts();
    }
    rawShiftsFinishedTime = std::clock();
    for (register unsigned __int32 forLoopTest = 0; forLoopTest < 0x008FFFFF; forLoopTest++)
    {
        testUnion();
    }
    unionFinishedTime = std::clock();
    std::printf(
        "Execution time for assigned shifts: %08u clocks\n"
        "Execution time for raw shifts:      %08u clocks\n"
        "Execution time for union:           %08u clocks\n\n"
        "Finished. Terminate!\n\n",
        assignedShiftsFinishedTime - startTime,
        rawShiftsFinishedTime - assignedShiftsFinishedTime,
        unionFinishedTime - rawShiftsFinishedTime);

    system("pause");
    return 0;
}

void testAssignedShifts()
{
    std::string invalidClsids("This is a test string");
    std::vector<BYTE> compressedBytes;
    DWORD invalidLength = (DWORD) invalidClsids.length();
    compressedBytes.push_back((BYTE)  invalidLength);
    compressedBytes.push_back((BYTE) (invalidLength >>= 8));
    compressedBytes.push_back((BYTE) (invalidLength >>= 8));
    compressedBytes.push_back((BYTE) (invalidLength >>= 8));
}
void testRawShifts()
{
    std::string invalidClsids("This is a test string");
    std::vector<BYTE> compressedBytes;
    DWORD invalidLength = (DWORD) invalidClsids.length();
    compressedBytes.push_back((BYTE) invalidLength);
    compressedBytes.push_back((BYTE) (invalidLength >>  8));
    compressedBytes.push_back((BYTE) (invalidLength >>  16));
    compressedBytes.push_back((BYTE) (invalidLength >>  24));
}

typedef union _choice
{
    DWORD dwordVal;
    BYTE bytes[4];
} choice;

void testUnion()
{
    std::string invalidClsids("This is a test string");
    std::vector<BYTE> compressedBytes;
    choice invalidLength;
    invalidLength.dwordVal = (DWORD) invalidClsids.length();
    compressedBytes.push_back(invalidLength.bytes[0]);
    compressedBytes.push_back(invalidLength.bytes[1]);
    compressedBytes.push_back(invalidLength.bytes[2]);
    compressedBytes.push_back(invalidLength.bytes[3]);
}

これを数回実行すると、次のようになります。

Execution time for assigned shifts: 00012484 clocks
Execution time for raw shifts:      00012578 clocks
Execution time for union:           00013172 clocks

Execution time for assigned shifts: 00012594 clocks
Execution time for raw shifts:      00013140 clocks
Execution time for union:           00012782 clocks

Execution time for assigned shifts: 00012500 clocks
Execution time for raw shifts:      00012515 clocks
Execution time for union:           00012531 clocks

Execution time for assigned shifts: 00012391 clocks
Execution time for raw shifts:      00012469 clocks
Execution time for union:           00012500 clocks

Execution time for assigned shifts: 00012500 clocks
Execution time for raw shifts:      00012562 clocks
Execution time for union:           00012422 clocks

Execution time for assigned shifts: 00012484 clocks
Execution time for raw shifts:      00012407 clocks
Execution time for union:           00012468 clocks

割り当てられたシフトと組合の間のタイについてのように見えます。後で値が必要になるので、union です! ありがとう!

ビリー3

4

7 に答える 7

8

これはおそらくあなたが得られるのと同じくらい最適化されています。ビット操作は、プロセッサで利用可能な最速の操作の一部です。

>>= 8 >>= 8 の代わりに >> 16、>> 24 の方が速いかもしれません - あなたは割り当てを削減します。

また、 & は必要ないと思います。BYTE ( 8 ビット文字である必要があります) にキャストしているため、とにかく適切に切り詰められます。(そうですか?間違っていたら訂正してください)

ただし、全体として、これらは本当にマイナーな変更です。プロファイリングして、実際に違いがあるかどうかを確認してください :P

于 2009-04-12T03:11:51.963 に答える
6

ユニオンを使用するだけです:

assert(sizeof (DWORD) == sizeof (BYTE[4]));   // Sanity check

union either {
    DWORD dw;
    struct {
         BYTE b[4];
    } bytes;
};

either invalidLength;
invalidLength.dw = (DWORD) invalidClsids.length();
compressedBytes.push_back(either.bytes.b[0]);
compressedBytes.push_back(either.bytes.b[1]);
compressedBytes.push_back(either.bytes.b[2]);
compressedBytes.push_back(either.bytes.b[3]);

注: 元の質問のビットシフト アプローチとは異なり、このコードはエンディアンに依存する出力を生成します。 これは、あるコンピューターで実行されているプログラムからの出力が、エンディアンが異なるコンピューターで読み取られる場合にのみ問題になります。 、 念のため。

于 2009-04-12T03:21:06.123 に答える
2

潜在的な改善を推測するのではなく測定する必要がありますが、最初に考えたのは、次のようにユニオンを実行する方が速いかもしれないということです。

typedef union {
    DWORD d;
    struct {
        BYTE b0;
        BYTE b1;
        BYTE b2;
        BYTE b3;
    } b;
} DWB;

std::vector<BYTE> compBytes;
DWB invLen;
invLen.d = (DWORD) invalidClsids.length();
compBytes.push_back(invalidLength.b.b3);
compBytes.push_back(invalidLength.b.b2);
compBytes.push_back(invalidLength.b.b1);
compBytes.push_back(invalidLength.b.b0);

これはプッシュバックの正しい順序かもしれませんが、念のため確認してください - CPU のエンディアンに依存します。

于 2009-04-12T03:27:30.990 に答える
1

本当に簡単な方法は、DWORD* (単一要素配列) を BYTE* (4 要素配列) として扱うことです。コードもはるかに読みやすくなっています。

警告: 私はこれをコンパイルしていません

警告: これにより、コードがバイト順に依存するようになります

std::vector<BYTE> compressedBytes;
DWORD invalidLength = (DWORD) invalidClsids.length();
BYTE* lengthParts = &invalidLength;
static const int kLenghtPartsLength = sizeof(DWORD) / sizeof(BYTE);
for(int i = 0; i < kLenghtPartsLength; ++i)
    compressedBytes.push_back(lengthParts[i]);
于 2009-04-12T03:21:27.620 に答える
0

一度に1バイトずつ行う必要がありますか?32 ビット全体を一度にストリームに memcpy() できる方法はありますか? ストリームに書き込んでいるバッファのアドレスがある場合は、それにコピーできますか?

于 2009-04-12T03:16:44.353 に答える
0

おそらく、32ビット変数ポインターを取得し、それをcharポインターに変換してcharを読み取り、ポインターに+1を追加して次のcharを読み取ることが可能です..ただの理論です:)それが機能しているかどうかわかりません

于 2011-01-06T12:00:37.450 に答える