clseek

C - Wrong read after lseek with define expression


I have a binary file from which I need to read timestamps. In particular, I'm trying to read the last record. Every record is 24 bytes long, the timestamp is in the first 8 bytes. Here's the code I wrote:

#define IDX_RS_LEN (unsigned int)(sizeof(unsigned long) * 3)

int main(int argc, char** argv)
{
   int fd;
   unsigned long rGmte;
   char filename[256];
   int offset;

   fd = open(filename, O_RDONLY);
   if (fd != -1) {
      offset = lseek(fd, -IDX_RS_LEN, SEEK_END);
      read(fd, &rGmte, sizeof(unsigned long));
      printf("offset:%d\trGmte: %lu\n", offset, rGmte);
   } else {
      printf("Error opening file\n");
   }
   close(fd);

   return 0;
}

But this gives me the following output:

offset:117384 rGmte: 0

Which is wrong. If I replace the expression in the define with the fixed value 24 I get the right output:

offset:117384 rGmte: 1606314900

Please also note that offset is the same in both cases, but the value read is different. Any idea?


Solution

  • You are using a wrong type to set the position / offset in lseek, you should use an off_t(signed long) not an unsigned int.

    Take a look to What happens when I assign a negative value to an unsigned int?

    The offset set to lseek should be -24:

    printf("Output: %ld\n", -(signed long)(sizeof(unsigned long) * 3));
    Output: -24
    

    but you are setting

    printf("Output: %ld\n", -(unsigned int)(sizeof(unsigned long) * 3));
    Output: 4294967272
    

    Switch from

    #define IDX_RS_LEN (unsigned int)(sizeof(unsigned long) * 3)
    
    int main(int argc, char** argv)
    {
       int fd;
       unsigned long rGmte;
       char filename[256];
       int offset;
    
       fd = open(filename, O_RDONLY);
       if (fd != -1) {
          offset = lseek(fd, -IDX_RS_LEN, SEEK_END);
    

    to

    #define IDX_RS_LEN (sizeof(unsigned long) * 3)
    
    int main(int argc, char** argv)
    {
       int fd;
       unsigned long rGmte;
       char filename[256];
       off_t offset = IDX_RS_LEN;
    
       fd = open(filename, O_RDONLY);
       if (fd != -1) {
          offset = lseek(fd, -offset, SEEK_END);
    

    and it should work: https://godbolt.org/z/hEG4xx