0

I am trying to write a program where I can copy an int into a char array, and then write that char array into a file using the write syscall. In another program I want to read the contents of the file into a char array, and then retrieve the int from the array. The thing that I am having trouble understanding is how to write the contents of the int into the array and how to read the int from the char array.

Here is what I have

writing to file:

int fd2 = open("file2.txt", O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); 
//create buff2 with 1024 chars and last 4 bytes as int
write(fd2, buff2, 1028); 

I'm not sure how to exactly implement the commented line

reading from file:

int fd2 = open("file2.txt", O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); 
char buff2[1028];
read(fd2, buff2, 1028);
int val = *((int)((buff2+1023)+sizeof(int))); // file contains exactly 1028 bytes. first 1024 are characters, next 4 is int
printf("%d\n", val);

The line where I am trying to read the integer gives me a compiler error saying invalid type argument of unary '*' (have 'int')

I would appreciate any help

RagHaven
  • 4,156
  • 21
  • 72
  • 113

2 Answers2

0

The compilation error itself can be easily fixed with int val = *(int*)(buff2+1024).

However, if you try to read/write an int value from/into an address which is not divisible by sizeof(int), then you will simply get the wrong outcome, or worse - a memory-access violation.

That is, unless the underlying HW architecture as well as the designated compiler at hand support unaligned load and store operations (which is mostly not the case).

Since you do not know the address of buff2, you cannot be sure that buff2+1024 points to an address which is divisible by sizeof(int). Therefore, you have to read/write the int value one char at a time:

char* pVal = (char*)&val;

// Read 'int' on little-endian architecture
for (i=0; i<sizeof(val); i++)
    pVal[i] = buff2[1024+i];

// Read 'int' on big-endian architecture
for (i=0; i<sizeof(val); i++)
    pVal[sizeof(val)-1-i] = buff2[1024+i];

// Write 'int' on little-endian architecture
for (i=0; i<sizeof(val); i++)
    buff2[1024+i] = pVal[i];

// Write 'int' on big-endian architecture
for (i=0; i<sizeof(val); i++)
    buff2[1024+i] = pVal[sizeof(val)-1-i];

If you declare buff2 as a global variable, then you can force the compiler to allocate it at an aligned memory address. For example, assuming that sizeof(int) == 4 on your platform:

char buff[1028] __attribute__ ((aligned(4)));

Then, you can safely read/write an int value from/into any offset that is divisible by sizeof(int):

// Read 'int'
val = *(int*)(buff2+1024);

// Write 'int'
*(int*)(buff2+1024) = val;
barak manos
  • 29,648
  • 10
  • 62
  • 114
  • Thank you! Before I can try this, how do I go about writing the int into char buffer, so that I can use the write syscall to write to the file? – RagHaven Nov 07 '14 at 20:21
  • @AndroidDev93: Please see updated answer... However, unless you are aiming to avoid 2 file operations, you can simply follow the comment on your question given by twalberg. – barak manos Nov 07 '14 at 20:42
  • @barakmanos Reading/writing an int from unaligned memory, while yes is likely to get crashes/undesired behavior just because of garbage data and possible access violations. Unless you're using a limited compiler, for say an embedded environment, normal compilers (even many assemblers), say gcc, clang, visual studio, are smart enough to generate instructions to handle unaligned load/stores (load the word which are being span region, and do shifts to get the range you want into a register). Depending on the hardware, it can cause **massive** slow downs though. – D'Nabre Nov 07 '14 at 20:50
  • @D'Nabre: I agree that compiling such code into unaligned load/store operations would result in degraded runtime performance. But I think that in many cases (including VS if I'm not mistaken), the generated code would not make use in such instructions (resulting in outright runtime errors). – barak manos Nov 07 '14 at 21:16
  • @barakmanos Unless you're dealing with memory-mapped I/O or something, I just don't see. I would be very interested if you had some examples (that's not challenging you for proof, I really am interested). – D'Nabre Nov 08 '14 at 07:50
  • @D'Nabre: An ARM-based cortex (in specific STM32, which I have personally worked with), does not support unaligned load and store operations. See the answer at http://stackoverflow.com/a/18269440/1382251. It is not my answer, but I'm pretty sure that I've answered similar questions quite a few times (on top of this one of course). – barak manos Nov 08 '14 at 09:17
  • In the embedded space, you get compilers with varying support for their architecture, and I wouldn't be surprised if one in that space finding some that didn't know about the alignment restrictions of the core and/or to synthesize the proper code to hide this limitation at the C-level. Embedded toolchains vary, and some can be real nightmares though. I've been lucky that the ones I've had to use have let me really abuse alignment issues to pack things into memory without any problems, but I wouldn't assume that for a given board. This is a limited toolchain concern (unless you're using asm). – D'Nabre Nov 08 '14 at 09:52
0

int val = *((int)((buff2+1023)+sizeof(int))); will not compile as it look like int val = *some_integer; and needs to be int val = *some_integer_pointer;

Using int val = *(int*)(buff2+1024), as suggest by @barak manos is a good first step. But it does not handle memory alignment issues well.

Rather than use a char* for "first 1024 are characters, next 4 is int", use a structure.

typedef struct AD93 {
  char ch[1024];
  int val; // or int32_t
} AD93_T;

AD93_T buff2;
write(fd2, &buff2, sizeof buff2);

read(fd2, &buff2, sizeof buff2);
printf("%d\n", buff2.val);
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256