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:

Code: Select all

struct foo {
 char bar[4];
 ...
};
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 :wink: