了解位和偏移量的 C 要求 [关闭]
Posted
技术标签:
【中文标题】了解位和偏移量的 C 要求 [关闭]【英文标题】:Understanding C Requirements of bits and offset [closed] 【发布时间】:2017-03-26 20:36:28 【问题描述】:我了解 C 语言的一般概念以及如何制作日志文件。读取/写入文件等。
我担心的是需要以下格式:
[![在此处输入图片描述][1]][1]
我现在已经完成了很多工作,但我关心如何在第一条记录之后附加到我的日志文件中。我增加文件的记录计数(在前 2 个字节中)并在其后写入第一条记录。然后我将如何设置添加 2nd/3rd/etc 记录以逐个显示?
//confirm a file exists in the directory
bool fileExists(const char* file)
struct stat buf;
return (stat(file, &buf) == 0);
int rightBitShift(int val, int space)
return ((val >> space) & 0xFF);
int leftBitShift(int val, int space)
return (val << space);
int determineRecordCount(char * logName)
unsigned char record[2];
FILE *fp = fopen(logName, "rb");
fread(record, sizeof(record), 1, fp);
//display the record number
int recordNum = (record[0] << 8) | record[1];
recordNum = recordNum +1;
return (recordNum);
void createRecord(int argc, char **argv)
int recordNum;
int aux = 0;
int dst;
char* logName;
char message[30];
memset(message,' ',30);
//check argument count and validation
if (argc == 7 && strcmp("-a", argv[2]) ==0 && strcmp("-f", argv[3]) ==0 && strcmp("-t", argv[5]) ==0)
//aux flag on
aux = 1;
logName = argv[4];
strncpy(message, argv[6],strlen(argv[6]));
else if (argc == 6 && strcmp("-f", argv[2]) ==0 && strcmp("-t", argv[4]) ==0)
logName = argv[3];
strncpy(message, argv[5],strlen(argv[5]));
else
printf("Invalid Arguments\n");
exit(0);
//check if log exists to get latest recordNum
if (fileExists(logName))
recordNum = determineRecordCount(logName);
printf("%i\n",recordNum);
else
printf("Logfile %s not found\n", logName);
recordNum = 1;
//Begin creating record
unsigned char record[40]; /* One record takes up 40 bytes of space */
memset(record, 0, sizeof(record));
//recordCount---------------------------------------------------------------------
record[0] = rightBitShift (recordNum, 8); /* Upper byte of sequence number */
record[1] = rightBitShift (recordNum, 0); /* Lower byte of sequence number */
//get aux/dst flags---------------------------------------------------------------
//get date and time
time_t timeStamp = time(NULL);
struct tm *date = localtime( &timeStamp );
if (date->tm_isdst)
dst = 1;
record[2] |= aux << 7; //set 7th bit
record[2] |= dst << 6; //set 6th
//timeStamp-----------------------------------------------------------------------
record[3] |= rightBitShift(timeStamp, 24);//high byte
record[4] |= rightBitShift(timeStamp, 16);
record[5] |= rightBitShift(timeStamp, 8);
record[6] |= rightBitShift(timeStamp, 0); //low byte
//leave bytes 7-8, set to 0 -----------------------------------------
record[7] = 0;
record[8] = 0;
//store message--------------------------------------------
strncpy(&record[9], message, strlen(message));
//write record to log-----------------------------------------------------------------
FILE *fp = fopen(logName, "w+");
unsigned char recordCount[4];
recordCount[0] = rightBitShift (recordNum, 8); /* Upper byte of sequence number */
recordCount[1] = rightBitShift (recordNum, 0); /* Lower byte of sequence number */
recordCount[2] = 0;
recordCount[3] = 0;
fwrite(recordCount, sizeof(recordCount), 1, fp);
fwrite(record, sizeof(record), 1, fp);
fclose(fp);
printf("Record saved successfully\n");
【问题讨论】:
嗨,欢迎来到 ***。我们更喜欢文字而不是图像。如果您要使用图像,请像我一样嵌入它。 总和可能是忽略进位/溢出或其补码的所有八位字节(作为无符号值)的加法。 [对于 IP,总和是 16 字节实体的总和] 你能链接到完整的规范吗?缺少一些细节。 您的格式有误。 “备用(3 个字节)”,但它只有两个字节,7 和 8。 我看到你有来自 reddit 的 cross-posted 这个。请告诉我们您这样做是为了避免重复工作。 【参考方案1】:注意:我以前从未在 C 语言中这样做过,对此持保留态度。
这是一种非常特殊的二进制格式,其中每个位都被精确计算。它使用Least-Significant-Bit numbering scheme (LSB 0),其中位的编号从7到0。
指定“高字节”在前意味着此格式为big-endian。最重要的位首先出现。这就像我们写数字的方式,四千、三百和二十一是 4321。1234 将是小端。例如,记录数和序列都是 16 位大端数。
最后,checksum 是从记录的其余部分计算出来的数字,以验证传输没有错误。规范定义了如何进行校验和。
你的工作是精确地重现这种格式,可能使用fixed-sized types found in stdint.h 或unsigned char
。例如,序列是uint16_t
或unsigned char[2]
。
生成记录的函数可能有这样的签名:
unsigned char *make_record( const char *message, bool aux );
用户只需向您提供消息和辅助标志。其余的你可以通过函数计算出来。您可能决定让它们传入时间戳和序列。重点是,该函数只需要传递数据,它负责格式化。
这种字节顺序意味着您不能只写出整数,它们可能是错误的大小或错误的字节顺序。这意味着任何多字节整数都必须先序列化,然后才能将它们写入记录。 This answer covers ways to do that,我将使用来自this answer 的那些,因为事实证明它们更方便一些。
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
unsigned char *make_record( const char *message, bool aux )
// Allocate and zero memory for the buffer.
// Zeroing means no risk of accidentally sending garbage.
unsigned char *buffer = calloc( 40, sizeof(unsigned char) );
// As we add to the buffer, pos will track the next byte to be written.
unsigned char *pos = buffer;
// I decided not make the user responsible for
// the sequence number. YMMV.
static uint16_t sequence = 1;
pos = serialize_uint16( pos, sequence );
// Get the timestamp and DST.
time_t timestamp = time(NULL);
struct tm *date = localtime( ×tamp );
// 2nd row is all flags and a bunch of 0s. Start with them all off.
uint8_t flags = 0;
if( aux )
// Flip the 7th bit on.
flags |= 0x80;
if( date->tm_isdst )
// Flip the 6th bit on.
flags |= 0x40;
// That an 8 bit integer has no endianness, this is to ensure
// pos is consistently incremented.
pos = serialize_uint8(pos, flags);
// I don't know what their timestamp format is.
// This is just a guess. It's probably wrong.
pos = serialize_uint32(pos, (uint32_t)timestamp);
// "Spare" is all zeros.
// The spec says this is 3 bytes, but only gives it bytes
// 7 and 8. I'm going with 2 bytes.
pos = serialize_uint16(pos, 0);
// Copy the message in, 30 bytes.
// strncpy() does not guarantee the message will be null
// terminated. This is probably fine as the field is fixed width.
// More info about the format would be necessary to know for sure.
strncpy( pos, message, 30 );
pos += 30;
// Checksum the first 39 bytes.
// Sorry, I don't know how to do 1's compliment sums.
pos = serialize_uint8( pos, record_checksum( buffer, 39 ) );
// pos has moved around, but buffer remains at the start
return buffer;
int main()
unsigned char *record = make_record("Basset hounds got long ears", true);
fwrite(record, sizeof(unsigned char), 40, stdout);
在这一点上,我的专业知识已经耗尽,我以前从未这样做过。我很感激人们修复编辑中的小错误并建议在 cmets 中执行此操作的更好方法,例如如何处理时间戳。也许其他人可以在另一个答案中介绍如何进行 1 的补码校验和。
【讨论】:
【参考方案2】:由于一个字节由 8 位(从 0 到 7)组成,因此您可以使用按位运算来按照您的规范要求修改它们。查看一般信息 (https://en.wikipedia.org/wiki/Bitwise_operations_in_C)。作为预览,您可以使用 >> 或
【讨论】:
以上是关于了解位和偏移量的 C 要求 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ 中使用带有多级指针和偏移量的 WriteProcessMemory()?
Mongo ObjectID:即使使用 pytz,“也无法比较原始偏移量和可感知偏移量的日期时间”