我想對任意大小的尖頭記憶體塊進行位移。我想關于這個問題的作業char被char我發現了這個解決方案,它的作品。
void rshift(void *self, int shift, size_t size) {
char *s = self;
bool take, pass;
for (int i = 0; i < shift; i ) {
take = false;
for (int j = 0; j < size; j , take = pass) {
pass = *(s j) & 1;
*(s j) >>= 1;
*(s j) ^= (-take ^ *(s j)) & (1 << (CHAR_BIT - 1));
}
}
}
self要移動的記憶體塊在哪里,size以chars為單位的大小以及shift要移動的位數。基本上我正在做的是,對于每個位元組,我將它移動一個,將丟失的位傳遞給下一個位元組。
但是這個演算法很糟糕,我認為它就像一個O(shift * size)或什么,我很確定整個事情都可以用 and 解決O(size)。
注意:我展示了右移,左移是完全一樣的
uj5u.com熱心網友回復:
首先,您不需要shiftloop。你可以先做一個模數:int n = shift % CHAR_BIT;和一個除法int m = shift / CHAR_BIT;。實際上,旋轉char變數k * CHAR_BIT次數相當于直接將位元組移動k. 此外,您可以直接確定using的n最低有效位。然后,可以通過簡單的左移 ( )直接進行位移位。最后,可以使用. 請注意,在這種情況下,前面的操作適用于更安全(比有符號)的變數,因為負有符號型別的右移是實作定義的*(s j)int pass = *(s j) & ((1 << n) - 1);n*(s j) >>= n;pass*(s j) |= pass << (CHAR_BIT - n));unsigned charchar. 這使得演算法O(size)及時運行。
優化是在 ifshift為 0memmove時不執行任何操作,否則使用whenn為 0。
另一種優化是作業在幾個char在使用更大的型別,同時專案一樣uint64_t。然而,這個假設CHAR_BIT是 8,世界上幾乎所有(理智的)現代處理器都是這種情況。但是,您應該非常小心地進行此優化,因為加載/存盤的值需要正確對齊并且型別雙關必須是安全的(使用smemcpy或unions)以免破壞嚴格的別名規則(導致未定義的行為) .
另一種優化是使用SIMD內在函式(如現代 x86-64 處理器上的SSE、AVX2或大多數 ARM 處理器上的NEON)。這種優化比處理更大的型別更有效,也更安全。但是,使用內在函式需要高級編程技能,并且會使代碼的可移植性降低并且通常幾乎不可讀。SSE/NEON 可以同時處理每個周期 16 個 8 位專案和 AVX2 最多 32 個 8 位專案,從而大大加快代碼速度。請注意,編譯器有時會自動為您執行此操作(假設啟用了優化標志)。
請注意,寫作s[j]而不是*(s j)更容易閱讀和更短。另請注意,該運算式-take ^ *(s j)肯定會導致實作定義的行為,因為-1可以在不同的體系結構上以不同的方式表示(參見二進制補碼和一個補碼),盡管幾乎所有現代處理器都使用二進制補碼。
uj5u.com熱心網友回復:
我不知道您必須以多快的速度進行這些轉變,但我有另一種方式來建議遵循一點 Python 風格。我建議的源代碼是一次性撰寫的,因此不精確,但給出了想法,其組成如下:兩個函式,其中一個將要移動的塊轉換為字串,反之亦然。在兩者之間,移位(左右)是通過 sprintf 完成的。其余的代碼都是 printf 來顯示結果。看一看:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *BitToChar(void *, size_t);
void *CharToBit(char *);
int main(void)
{
uint8_t block[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81};
uint8_t *new_block;
size_t blk_len = sizeof(block) / sizeof(uint8_t);
char *CnvBit, *NewBits;
int shift = 8, cut;
printf("\nbit to shift: ");
scanf("%d", &shift);
if(shift <= 0)
{
printf("\nno need shift\n");
return 0;
}
printf("\noriginal: ");
for(int i = 0; i < blk_len; i )
printf("0xX ", block[i]);
printf("\n");
if((CnvBit = BitToChar(block, blk_len)) == NULL)
return -1;
if((NewBits = malloc(1 strlen(CnvBit))) == NULL)
return -1;
sright:
{
cut = strlen(CnvBit) - shift;
sprintf(NewBits, "%0*d%*.*s", shift, 0, cut, cut, CnvBit);
if((new_block = CharToBit(NewBits)) == NULL)
return -1;
}
printf("\nshift - bit right: ", shift);
for(int i = 0; i < blk_len; i )
printf("0xX ", new_block[i]);
printf("\n");
free(new_block);
sleft:
{
sprintf(NewBits, "%s%0*d", &NewBits[shift], shift, 0);
if((new_block = CharToBit(NewBits)) == NULL)
return -1;
}
printf("\nshift back - bit left: ", shift);
for(int i = 0; i < blk_len; i )
printf("0xX ", new_block[i]);
printf("\n");
free(new_block);
free(CnvBit);
free(NewBits);
return 0;
}
char *BitToChar(void *blk, size_t blk_len)
{
typedef uint8_t *arr;
char *result, *p;
if((result = malloc(1 (8 * blk_len))) == NULL)
return (char *)NULL;
arr arr_blk = blk;
p = result;
for(int j = 0; j < blk_len; j )
for(int k = 7; k >= 0; k--)
*p = (arr_blk[j] & (uint8_t)(1 << k)) ? '1' : '0';
*p = '\0';
return result;
}
void *CharToBit(char *BitStr)
{
size_t bs_len = strlen(BitStr);
size_t blk_len = (bs_len / 8 ) ((bs_len % 8) ? 1 : 0);
uint8_t *block, *p;
if((block = calloc(blk_len, sizeof(uint8_t))) == NULL)
return (void *)NULL;
p = BitStr;
for(int j = 0; j < blk_len && *p != '\0'; j )
for(int k = 7; k >= 0; k--)
block[j] |= (*p - '0') << k;
return block;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/378662.html
下一篇:在匯編語言中確定回傳值時遇到問題
