将单个字节连接到字节序列

时间:2016-02-12 04:14:59

标签: c bit-manipulation

新来的,如果我没有恰当地问我的问题,请告诉我。

我试图从文件数据动态创建一个字节序列。这里有一些我遇到问题的代码(我知道打印是一种糟糕的调试方式,但问题似乎微不足道,而且我没有看到很多其他的gdb)。编辑包含编译的示例。实际代码要长得多,并不想给任何人带来负担。

#include <stdio.h>
#include <stdlib.h>

int main() {
  FILE *fpt;
  unsigned char *file;
  int file_size, i;

  // File ops
  fpt = fopen("test.txt", "rb");
  fseek(fpt, 0L, SEEK_END);
  file_size = ftell(fpt);   
  fseek(fpt, 0L, SEEK_SET);
  file = (unsigned char *) calloc(sizeof(unsigned char), file_size);
  fread(file, file_size, sizeof(unsigned char), fpt);   
  fclose(fpt);

  int str_len = 1;
  unsigned char *string = (unsigned char *)calloc(sizeof(unsigned char), str_len);
  unsigned char *next_byte = (unsigned char *)calloc(sizeof(unsigned char),1);
  i = 1;
  *string = *file;  

  // Build byte sequence
  while (i < file_size) {
    *next_byte = *(file + i);
    str_len++;
    string = realloc(string, str_len);
    if (i==1)printf("string+char = %04X\n",  (*string << 8) | *next_byte);
    *string = (*string << 8) | *next_byte;
    if (i==1)printf("string+char = %04X\n", *string);
    i++;
  }
  return 0;
}
// I realize I need to free memory

说我的test.txt只包含

ABC

用十六进制编辑器查看我会看到

41 42 43 0A

两张照片的输出是:

string + char = 4142   string + char = 0042

我的问题是,为什么第一张印刷品会给出我想要的结果,而第二张印刷品却没有?我意识到无符号字符是一个字节,因此向左移位8位应该给我零。我不明白为什么直接打印位操作会给我带来我想要的结果。

有没有更好的方法将单个字节连接到字节序列?

1 个答案:

答案 0 :(得分:0)

这对我来说有点困惑。

我无法看到代码示例的效果与您预期的不同。
让我举例说明......

我在示例代码中添加了一些打印件,请参阅下面的 concat.c 以了解完整程序,但我们只关注while循环的转换。 fyi,到目前为止的所有内容(从&#34加载4个字节; test.txt&#34;等等)似乎按预期工作。

以下是具体的代码片段:

移位片段,原始

if (i==1)printf("string+char = %04X\n",  (*string << 8) | *next_byte);
*string = (*string << 8) | *next_byte;
if (i==1)printf("string+char = %04X\n", *string);

我认为你的带有%04x的printf()表明 * string 中的内容比实际存在的更多。

转移片段,修订

我修改了shift表达式,使用一系列单独的变量来分解我认为它正在做的事情,所以我可以查看每个变量的值。

       /* original:  *string = (*string << 8) | *next_byte; */
       printf("   explicit shifting...\n");
       unsigned char a = *string;
       printf("      Lets print 'a' as %%x and %%04x just to verify zero padding doesn't change anything.\n");
       printf("      a=%x  a=%04x  sizeof(a)=%ld\n", a, a, sizeof(a) );
       unsigned char b = a << 8;
       printf("      b=%x       : b = a << 8 yielded all zero bits.\n", b);
       unsigned char c = *next_byte;
       printf("      c=%x       : c = *next_byte as expected.\n", c);
       unsigned char d = b | c;
       printf("      d=%x       : d bitwise-or of 0 w/c yields, well, c.\n", d);
       // pick up with original...
       // note that we're always overwriting string[0]. 
       // the following is the same as saying:
       //     string[0] = d; // assuming 'd' is assigned as above.
       *string = (*string << 8) | *next_byte;
       // If you want to use shift and accumulate 4 bytes
       // you probably want *string to be a long.
       printf("   after shift: string[0]=%x, next_byte[0]=%x\n", string[0], next_byte[0] );
       if (i==1) printf("string+char = %04X\n", *string);
从移位片段输出

,修改

以下是第一次通过while循环。
i = 1,next_byte = 0x42。
(见下面的完整输出)

   explicit shifting...
      Lets print 'a' as %x and %04x just to verify zero padding doesn't change anything.
      a=41  a=0041  sizeof(a)=1
      b=0       : b = a << 8 yielded all zero bits.
      c=42       : c = *next_byte as expected.
      d=42       : d bitwise-or of 0 & c yields, well, c.
   after shift: string[0]=42, next_byte[0]=42
string+char = 0042

原始程序的最后一行显示 string + char = 0042 但不是因为printf格式是 printf(&#34; string + char = %04X \ n&#34;,* string); ?我的意思是...... * string 的基础值只是0x42,这应该是它应该做的,是吗?

现在说过,我不认为这是关于&#34;转移&#34;因为它不断地覆盖字符串的第一个字节,例如串[0]。

也许这是实际问题?

这是另一个输出片段,这是我在下面的while循环之后添加的一些打印件(再次参见concat.c)中的完整代码。

After while loop.  just for fun, let's print out string...
   string[0]=0a  (string+0)=0x114d010
   string[1]=00  (string+1)=0x114d011
   string[2]=00  (string+2)=0x114d012
   string[3]=00  (string+3)=0x114d013
done.
$ 

在这里你可以看到 string 的值非常空。
string 确实保留了最后一个字符0x0a。
由于我不清楚的原因, string 初始化为第一个字符,&#39; A&#39;,之前 while循环开始。好歹...
在while循环期间, string 已多次重新分配。 (例如 string = realloc(string,str_len); - 为什么这样做,顺便说一下?)

所以...你想要转变和放大吗?按位或级联字符&#34; ABC \ n&#34;跨字符串

如果你有 long my4bytes; 而不是 string ,我可以看到移动和放大按位 - 或者&#34;有用&#34;收集个别字节。
但是......字符串本质上是一个字节数组(ok,unsigned char数组)。

假设您想将 string 保留为字节数组,我认为您最好只做以下操作: string [i] = * next_byte;


大二有很多方法可以写出来; while循环有点乱,所以我会把它留给你。 (这是可以理解的......我可以想象杂乱的原因是因为原始的例子你把它缩小到足以在原始问题中发布的东西)。


无论如何,这有助于您指明有用的方向吗?
或者......我是否错过了原始问题的意图?

来自concat.c的样本输出

$ cat test.txt 
ABC
$ hexdump -C test.txt
00000000  41 42 43 0a                                       |ABC.|
00000004
$ gcc concat.c 
$ ./a.out
file_size=4
   file[0]=41  (file+0)=0x114d240
   file[1]=42  (file+1)=0x114d241
   file[2]=43  (file+2)=0x114d242
   file[3]=0a  (file+3)=0x114d243

--- Build byte sequence
while: i=1
   file[i]=42  file=0x114d240
   next_byte[0]=42  next_byte=0x114d030
string+char = 4142
   before shift: string[0]=0041, next_byte[0]=0042
   explicit shifting...
      Lets print 'a' as %x and %04x just to verify zero padding doesn't change anything.
      a=41  a=0041  sizeof(a)=1
      b=0       : b = a << 8 yielded all zero bits.
      c=42       : c = *next_byte as expected.
      d=42       : d bitwise-or of 0 w/c yields, well, c.
   after shift: string[0]=42, next_byte[0]=42
string+char = 0042
while: i=2
   file[i]=43  file=0x114d240
   next_byte[0]=43  next_byte=0x114d030
   before shift: string[0]=0042, next_byte[0]=0043
   explicit shifting...
      Lets print 'a' as %x and %04x just to verify zero padding doesn't change anything.
      a=42  a=0042  sizeof(a)=1
      b=0       : b = a << 8 yielded all zero bits.
      c=43       : c = *next_byte as expected.
      d=43       : d bitwise-or of 0 w/c yields, well, c.
   after shift: string[0]=43, next_byte[0]=43
while: i=3
   file[i]=0a  file=0x114d240
   next_byte[0]=0a  next_byte=0x114d030
   before shift: string[0]=0043, next_byte[0]=000a
   explicit shifting...
      Lets print 'a' as %x and %04x just to verify zero padding doesn't change anything.
      a=43  a=0043  sizeof(a)=1
      b=0       : b = a << 8 yielded all zero bits.
      c=a       : c = *next_byte as expected.
      d=a       : d bitwise-or of 0 w/c yields, well, c.
   after shift: string[0]=a, next_byte[0]=a

After while loop.  just for fun, let's print out string...
   string[0]=0a  (string+0)=0x114d010
   string[1]=00  (string+1)=0x114d011
   string[2]=00  (string+2)=0x114d012
   string[3]=00  (string+3)=0x114d013
done.
$ 

concat.c

#include <stdio.h>
#include <stdlib.h>

int main() {
   FILE *fpt;
   unsigned char *file;
   int file_size, i;

   // File ops
   fpt = fopen("test.txt", "rb");
   fseek(fpt, 0L, SEEK_END);
   file_size = ftell(fpt); 
   printf("file_size=%d\n", file_size);
   fseek(fpt, 0L, SEEK_SET);
   //file = (unsigned char *) calloc(sizeof(unsigned char), file_size);
   file = calloc( file_size, file_size);
   fread(file, file_size, sizeof(unsigned char), fpt); 
   fclose(fpt);

   int str_len = 1;
   unsigned char *string = 
      (unsigned char *)calloc(sizeof(unsigned char), str_len);
   unsigned char *next_byte = 
      (unsigned char *)calloc(sizeof(unsigned char),1);
   i = 1;
   //printf("          file[0]=%02x  file=%p\n", file[0], file );
   //printf("before: string[0]=%02x  string=%p\n", string[0], string );
   *string = *file;  
   //printf("after:  string[0]=%02x  string=%p\n", string[0], string );

   for( int idx = 0; idx < file_size; ++idx ) {
      printf("   file[%d]=%02x  (file+%d)=%p\n", idx, file[idx], idx, (file+idx) );
   }
   printf("\n--- Build byte sequence\n");
   while (i < file_size) {
       printf("while: i=%d\n", i );
       printf("   file[i]=%02x  file=%p\n", file[i], file );
       *next_byte = *(file + i);
       printf("   next_byte[0]=%02x  next_byte=%p\n", next_byte[0], next_byte );
       str_len++;
       string = realloc(string, str_len);
       if (i==1) printf("string+char = %04X\n",  (*string << 8) | *next_byte);
       printf("   before shift: string[0]=%04x, next_byte[0]=%04x\n", string[0], next_byte[0] );
       /* original:  *string = (*string << 8) | *next_byte; */
       printf("   explicit shifting...\n");
       unsigned char a = *string;
       printf("      Lets print 'a' as %%x and %%04x just to verify zero padding doesn't change anything.\n");
       printf("      a=%x  a=%04x  sizeof(a)=%ld\n", a, a, sizeof(a) );
       unsigned char b = a << 8;
       printf("      b=%x       : b = a << 8 yielded all zero bits.\n", b);
       unsigned char c = *next_byte;
       printf("      c=%x       : c = *next_byte as expected.\n", c);
       unsigned char d = b | c;
       printf("      d=%x       : d bitwise-or of 0 w/c yields, well, c.\n", d);
       // pick up with original...
       // note that we're always overwiting string[0]. 
       // the following is the same as saying:
       //     string[0] = d; // ssuming 'd' is assigned as above.
       *string = (*string << 8) | *next_byte;
       // If you want to use shift and accumulate 4 bytes
       // you probably want *string to be a long.
       printf("   after shift: string[0]=%x, next_byte[0]=%x\n", string[0], next_byte[0] );
       if (i==1) printf("string+char = %04X\n", *string);
       i++;
   }
   printf("\nAfter while loop.  just for fun, let's print out string...\n");
   for(int idx = 0; idx < str_len; ++idx ) {
      printf("   string[%d]=%02x  (string+%d)=%p\n", idx, string[idx], idx, (string+idx) );
   }
   printf("done.\n");
   return 0;
}
// I realize I need to free memory

P.S。打印实际上是一种很好的排除故障的方法;不要犹豫,继续添加它们,直到你的代码正在做什么变得非常明显。