Search code examples
cpointersbitmapfile-handlinglseek

lseek() Trying to use with a byte file but pointer is of FILE type


This is for a project for everyone's awareness. It's my first project in C and have a question regarding lseek() and moving the file pointer.

Right now I'm able to read the bitmap and DIB header of a bitmap file. I need to now traverse the pixels and manipulate them in certain ways. I have written out in pseudocode how I plan to tackle the manipulation. But I am having difficulty understanding how to properly use lseek, as I keep getting incompatible pointer to integer conversion... warnings with my code. I'll give a short example of my main method since this is for a project:

int main(int argc, const char * argv[]) {

    FILE *fp;

    if((fp = fopen(argv[1], "r+b")) == NULL){
        printf("Error:  Unable to open file.\n");
        exit(0);
    }

    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    rewind(fp);

    char test;  // simply to test overwriting the current byte

    fread(&test, sizeof(char), 1, fp);
    test = ~test;
    lseek(fp, -1, SEEK_CUR); //produces error
    //also tried fseek prior to realizing I should be using lseek to move my pointer.
    fwrite(&test, 1, sizeof(char), fp);

    fclose(fp);
    return 0;
}

Again, not trying to provide too much of my code since this is a project. But I'd like help understanding how to properly use lseek please. I noticed that it returns an int value, so I know that it is because my file pointer is of type FILE. But what is the proper way to use this method? I saw one example that had opened the same file in both read and write mode, where write mode was using lseek. But for some reason I don't know if that is correct or not.

EDITED Based on two members response, I changed my code above to:

rewind(fp);
lseek(fileno(fp), hdr.offset, SEEK_CUR); //hdr.offset == 54 bytes
printf("FD FILENO:  %d\n", fileno(fp)); // prints 3???
printf("CURRENT POS: %p\n", fp);  //prints 0x7fffe7eae0b0 (I understand it's an address)
fread(&test, sizeof(char), 1, fp);
lseek(fileno(fp), -1, SEEK_CUR);
fwrite(&test, 1, sizeof(char), fp);
printf("CURRENT POS: %p\n", fp);  //prints the same address as above?

What am I not getting other than everything to do with C?


Solution

  • If you'd like to keep using FILE *fp, which is probably a good idea, you can get convert fp to its corresponding int file descriptor with int fileno(FILE *stream). In other words,

    lseek(fileno(fp), -1, SEEK_CUR); 
    

    Added

    All works fine with fseek.

    #include <stdio.h>
    
    int main(int argc, const char *argv[]) {
      if (argc < 2) {
        fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
        return 1;
      }
      FILE *fp;
      if((fp = fopen(argv[1], "r+b")) == NULL){
        fprintf(stderr, "Error:  Unable to open fle '%s'.\n", argv[1]);
        return 1;
      }
      char buf[17];
      size_t n_read = fread(buf, sizeof(char), sizeof buf - 1, fp);
      buf[n_read] = '\0';
      printf("Initial contents: %s\n", buf);
    
      fseek(fp, 0, SEEK_END);
      long fsize = ftell(fp);
      printf("Position at end of file: %ld\n", fsize);
    
      // Read first character in file.
      rewind(fp);
      char test;
      fread(&test, sizeof(char), 1, fp);
    
      ++test;
      fseek(fp, -1, SEEK_CUR);
      fwrite(&test, sizeof(char), 1, fp);
    
      rewind(fp);
      n_read = fread(buf, sizeof(char), sizeof buf - 1, fp);
      buf[n_read] = '\0';
      printf("Final contents: %s\n", buf);
    
      fclose(fp);
      return 0;
    }
    

    And then

    $ gcc foo.c -o foo
    $ ./foo foo.c
    Initial contents: #include <stdio.
    Position at end of file: 881
    Final contents: $include <stdio.