Accessing a char array as ints

Programming, for all ages and all languages.
Post Reply
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Accessing a char array as ints

Post 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.
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Post 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();
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post 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).
Every good solution is obvious once you've found it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Post 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
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Post 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..
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Post 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?!
Last edited by FlashBurn on Fri May 02, 2008 8:09 am, edited 1 time in total.
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Post 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");
}
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

The union solution is the correct way to do it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Post 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).
User avatar
edfed
Member
Member
Posts: 42
Joined: Wed Apr 09, 2008 5:44 pm
Location: Mars

Post 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.
welcome in my dream.
User avatar
edfed
Member
Member
Posts: 42
Joined: Wed Apr 09, 2008 5:44 pm
Location: Mars

Post 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.
welcome in my dream.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post 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.
User avatar
Zenith
Member
Member
Posts: 224
Joined: Tue Apr 10, 2007 4:42 pm

Post 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:
"Sufficiently advanced stupidity is indistinguishable from malice."
Post Reply