Page 1 of 1
Accessing a char array as ints
Posted: Fri May 02, 2008 6:03 am
by FlashBurn
I have a structure in memory and the first 4 bytes are a string and I defined the structures this way:
But how can I access these 4 chars within 1 run? I mean I like to compare these 4 chars with an constant string and in assembly I´m comparing the register where I loaded the first 4 bytes with this constant, but how to do that in C?
Edit::
I use a pointer of the structure which points to the memory where the structure is.
Posted: Fri May 02, 2008 6:16 am
by Korona
If the structure is packed, you can use:
Code: Select all
foo *pointer; // your pointer
if(0x12345678 == *((int*)pointer)) do_something();
But that's not very pretty code. Why not use usual comparisons?
Code: Select all
if(pointer->bar[0] == 'A'
&& pointer->bar[1] == 'B'
&& pointer->bar[2] == 'A'
&& pointer->bar[3] == 'A') do_something();
Posted: Fri May 02, 2008 6:23 am
by Solar
Check out the "union" data type. What you are looking for is a union of char[4] with int (or rather, uint32_t - remember that "int" doesn't have to mean 4 bytes on all platforms).
Posted: Fri May 02, 2008 6:39 am
by FlashBurn
@Korona
GCC wont optimize the usual comparisons into one 32bit comparison, but I took your first solution and gcc is compiling it right, but I still have to test if it works.
@Solar
I took a look at unions, but I don´t see how they can help here!?
@all
I could also use a "strncmp", but this would be overhead for only searching a 4byte String.
Edit::
The Solution of Korona doesn´t work, it only works if I write 4 normal comparisons
Posted: Fri May 02, 2008 7:40 am
by Brynet-Inc
Code: Select all
#include <stdio.h>
#include <stdint.h>
struct foo {
uint8_t bar[4];
} __packed;
int main(void) {
struct foo local_foo;
*(uintptr_t *)&local_foo.bar = 0xffffffff;
printf("%lx\n", *(uintptr_t *)&local_foo.bar);
return 0;
}
Rainy days impair my brain, I do not know why..
Hope this helps..
Posted: Fri May 02, 2008 7:52 am
by FlashBurn
Ok, this is my code:
Code: Select all
struct foo *ptr= 0xf0000;
while(strncmp((char *)&foo->bar,"TEST",4) != 0) {
code ...
}
return ptr;
I use the "fno-builtin" option for gcc, so he has to call my strncmp function, but if I don´t use it, he inserts a "rep cmpsb" opcode. Why is he so dump to use the byte compare and not the dword compare and why doesn´t he recognize that I only want to compare 4bytes and makes a compare with a constant?
Another question is, can I use gcc w/o "fno-builtin" when I write my kernel? I mean he is only optimizing the functions away, isn´t he?!
Posted: Fri May 02, 2008 8:04 am
by Korona
FlashBurn wrote:The Solution of Korona doesn´t work, it only works if I write 4 normal comparisons
It works perfectly on my machine. Remember that you have to swap the bytes of the integer as x86 is little endian.
Code: Select all
#include <stdio.h>
struct foo {
char bar[4];
} __attribute__((packed));
int main() {
struct foo object;
object.bar[0] = 0;
object.bar[1] = 1;
object.bar[2] = 2;
object.bar[3] = 3;
struct foo *pointer = &object;
if(0x03020100 == *((int*)pointer))
printf("It works!\n");
}
However Solars solution is better than mine of course:
Code: Select all
#include <stdio.h>
struct foo {
union {
char bar[4];
int barbits;
};
};
int main() {
struct foo object;
object.bar[0] = 0;
object.bar[1] = 1;
object.bar[2] = 2;
object.bar[3] = 3;
struct foo *pointer = &object;
if(0x03020100 == pointer->barbits)
printf("It works!\n");
}
Posted: Fri May 02, 2008 8:19 am
by JamesM
The union solution is the correct way to do it.
Posted: Fri May 02, 2008 8:19 am
by FlashBurn
Thanks, the problem was the byte swapping I forgot
Now it works.
Edit::
I dislike the union solution. I switched over to C because I wanted to write my code faster and I wanted to write code which is easier to read (before I´ve written my code in assembly).
Posted: Fri May 02, 2008 9:23 am
by edfed
in assembly I´m comparing the register where I loaded the first 4 bytes with this constant
simply, do it in assembly.
i know it is possible to build ASM functions into C++.
Code: Select all
asm:
.foo=esp+4
.const=esp+8
mov eax,[.foo]
cmp eax,[.const]
mov eax,0
je @f
mov eax,-1
@@:
ret 8
ps: i never code with stack frames as for me, stack is only to save tmp values.
then don't be disapointed if labels values are wrong.
Posted: Fri May 02, 2008 9:26 am
by edfed
edfed wrote:in assembly I´m comparing the register where I loaded the first 4 bytes with this constant
simply, do it in assembly.
i know it is possible to build ASM functions into C++.
Code: Select all
asm;
{
.foo=esp+4
.const=esp+8
mov eax,[.foo]
cmp eax,[.const]
mov eax,0
je @f
mov eax,-1
@@:
ret 8
}
assembly is not that hard to read. what is hard is to play with too much abstraction levels.
ps: i never code with stack frames as for me, stack is only to save tmp values.
then don't be disapointed if labels values are wrong.
Posted: Fri May 02, 2008 9:29 am
by JamesM
edfed wrote:in assembly I´m comparing the register where I loaded the first 4 bytes with this constant
simply, do it in assembly.
i know it is possible to build ASM functions into C++.
Code: Select all
asm:
.foo=esp+4
.const=esp+8
mov eax,[.foo]
cmp eax,[.const]
mov eax,0
je @f
mov eax,-1
@@:
ret 8
ps: i never code with stack frames as for me, stack is only to save tmp values.
then don't be disapointed if labels values are wrong.
That is a horrible, horrible solution. The OP knows assembly, but he wants to use C. So a C solution is far better.
Posted: Fri May 02, 2008 1:18 pm
by Zenith
Also, a decent compiler should create machine code in such a way that it will optimally fit in with the function and the code surrounding it. You're also pointlessly overriding the compiler (which is also most likely better at assembly than a majority of so-called 'assembly programmers').
And I don't see your problem with unions. They conserve memory as well as enabling the compiler to optimize memory accesses.
Note that a union does not have to be located inside a struct, and that in 'strict' C that it cannot be anonymous.
Good luck