2017-03-26 6 views
1

C의 일반적인 개념과 로그 파일을 만드는 방법을 이해합니다. 파일을 읽고 쓰는 것.C 비트 및 오프셋 요구 사항

내 관심이 요구되는 다음과 같은 형식입니다 :

[! [] 여기에 이미지 설명을 입력 [1] [1]

나는 좋은 덩어리가 지금은 수행하지만,와 걱정 왔 첫 번째 레코드 다음에 내 로그 파일에 추가하는 방법. 파일의 레코드 수 (상위 2 바이트)를 증가시키고 그 뒤에 첫 번째 레코드를 씁니다. 어떻게하면 두 번째/세 번째/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"); 
} 
+1

안녕하십니까, StackOverflow에 오신 것을 환영합니다.우리는 이미지에 텍스트를 선호합니다. 이미지를 사용하려는 경우 이미지를 삽입하십시오. – Schwern

+0

합계는 아마도 carry/overflow 또는 그 보수를 무시하고 (부호없는 값으로) 모든 옥텟을 추가 한 것입니다. [IP 용 합계가 16 바이트 항목에 합산되었습니다] – wildplasser

+0

전체 사양에 연결할 수 있습니까? 세부 사항이 누락되었습니다. – Schwern

답변

0

바이트가 (0 ~ 7) 8 비트로 구성되어 당신이 당신의 사양 요구로 수정하는 비트 연산을 사용할 수있다. 일반 정보 (https://en.wikipedia.org/wiki/Bitwise_operations_in_C)를 찾아보십시오. 미리보기에서 >> 또는 < < 연산자를 사용하여 수정할 비트를 결정하고 논리 연산자 | &을 사용하여 값을 설정하십시오.

1

참고 : 이전에는 C에서 이것을 한 번도 해본 적이 없었습니다.

이것은 각 비트를 정확하게 설명하는 매우 구체적인 이진 형식입니다.

"상위 바이트"가 먼저 오도록 지정하는 것은이 형식이 big-endian임을 의미합니다. 가장 중요한 비트가 먼저옵니다. 이것은 숫자를 쓰는 방법과 같습니다. 4 천 1 백 3 십 2는 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(&timestamp); 

    // 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); 
} 

이 시점에서 내 전문 기술은 고갈되었습니다. 이전에는이 ​​작업을 수행하지 않았습니다. 나는 편집에서의 작은 실수를 고치고, 타임 스탬프로 무엇을 할 것인가와 같은 코멘트에서 그것을하는 더 좋은 방법을 제안하는 사람들에게 감사 할 것입니다. 그리고 다른 사람이 다른 답변에서 1의 칭찬 체크섬을 수행하는 방법을 설명 할 수 있습니다.