distributing data across a structure (new to c please help)

113 views
Skip to first unread message

nwdpil

unread,
Aug 9, 2012, 9:32:00 PM8/9/12
to
the ulimate goal is to read the MZ header from a binary windows pe file, which is simple enough. anyway the theory goes (and this is the bit i dont understand im new to c programming) i memcpy the data from the file ACROSS a struct. is this possible? i dont understand how to initialise and manipulate the struct. can i copy a set of data that is 16bytes long, to a struct with two 8byte children and will memcpy then distribute the data for me if i pass it pointers?

it sounds easy but im really struggling to get to grips with it. anyway heres a simple c program i wrote to demonstrate the concept. it fails with the error Run-Time Check Failure #3 - The variable 'x' is being used without being initialized.

for example i should be able to access string "00004444" with x->b; and "eeeeffff" with x->bb;

im on windows running visual c++ 2010 express, although im coding purely in c because i never saw the point in object orientated programming.

help please?

[code]
// pointblank.c : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

typedef struct _test {
char b[8];
char bb[8];
}; test, *ptest;

int _tmain(int argc, _TCHAR* argv[])
{
struct _test * x;
char* s[16] = {"00004444eeeeffff"};
memcpy (x,s,16);

return 0;
}
[/code]

i honestly dont get it, if you could spend five minutes coding it for me so i can learn from reading your code would be excellent. this is a large scale project im working on but im totally new to c so its a bit... odd for me. im trying to write a pe file disassembler (just so you know). why? why the heck not? - nwdpil
--
comp.lang.c.moderated - moderation address: cl...@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.

James Kuyper

unread,
Aug 10, 2012, 1:43:26 AM8/10/12
to
On 08/09/2012 09:32 PM, nwdpil wrote:
> the ulimate goal is to read the MZ header from a binary windows pe file, which is simple enough. anyway the theory goes (and this is the bit i dont understand im new to c programming) i memcpy the data from the file ACROSS a struct. is this possible? i dont understand how to initialise and manipulate the struct. can i copy a set of data that is 16bytes long, to a struct with two 8byte children and will memcpy then distribute the data for me if i pass it pointers?
>
> it sounds easy but im really struggling to get to grips with it. anyway heres a simple c program i wrote to demonstrate the concept. it fails with the error Run-Time Check Failure #3 - The variable 'x' is being used without being initialized.
>
> for example i should be able to access string "00004444" with x->b; and "eeeeffff" with x->bb;
>
> im on windows running visual c++ 2010 express, although im coding purely in c because i never saw the point in object orientated programming.
>
> help please?
>
> [code]
> // pointblank.c : Defines the entry point for the console application.
> //
>
> #include "stdafx.h"
> #include "stdio.h"
> #include "stdlib.h"
> #include "string.h"
>
> typedef struct _test {
> char b[8];
> char bb[8];
> }; test, *ptest;
>
> int _tmain(int argc, _TCHAR* argv[])
> {
> struct _test * x;
> char* s[16] = {"00004444eeeeffff"};
> memcpy (x,s,16);
>
> return 0;
> }
> [/code]
>
> i honestly dont get it, if you could spend five minutes coding it for me so i can learn from reading your code would be excellent. this is a large scale project im working on but im totally new to c so its a bit... odd for me. im trying to write a pe file disassembler (just so you know). why? why the heck not? - nwdpil

I know nothing about Windows pe files. Insofar as your question is about
them, it would be better to post this question in a Windows oriented group.

However, there seem to be some very basic C issues here that I can address.

The identifier _tmain is reserved to the implementation for use at file
scope; the identifier _TCHAR is reserved to the implementation for all
uses. Your use of those identifiers renders the behavior of your program
undefined, as far as the C standard is concerned. I would guess that
Windows defines the behavior that C leaves undefined, so those are
probably not really problems.

However, your use of _test for the struct tag violates the same rule as
_tmain does, but it seems unlikely to me to have been given a special
Windows meaning. Change it. As a general rule of thumb, avoid naming
anything with an initial '_'. Some things you must use are defined by
the system to have names starting with '_', but never define anything of
your own with such a name.

The ';' after your struct definition is a syntax error; remove it.

You've set up "struct _test" and "test" as two different names for the
same type. Why do you need two names? either remove "_test", or remove
"typedef" and "test". Some people set up the typedef name and the struct
tag to be the same: this is allowed by the C standard, though it's still
pointless. It won't confuse your compiler (thought it might confuse a
human reader).

In principle, compilers are allowed to insert arbitrary unpredictable
amounts of padding between members of a struct. In practice, that's
unlikely to come up in this particular case, but you should not get into
the habit of ignoring that possibility. Because of the padding, the
memcpy() will not necessarily do what you want it to do, which is why
this is a bad idea.

You've declared 'x' to be a pointer; it's supposed to point at a
structure. You never set it to point at anything. Then you tell memcpy()
to copy s to the location pointed at by 'x'. Because 'x' doesn't point
at anything yet, the behavior of your code is undefined.

You've defined 's' to be an array of 16 pointers to char, You've
initialized it with a single pointer to char, which points at the string
"00004444eeeeffff", which is stored in some unspecified location in
memory. s[0] contains that pointer; s[1] through s[15] are all
implicitly initialized with null pointers. Your memcpy() command did not
copy the string, but only the first 16 bytes of that array of pointers
to strings. If you were, for instance, using a typical system where
sizeof(char*) == 4, then the first four bytes you copied over would be
from the first pointer, the next 12 bytes would be copies of the first
three null pointers.

I strongly suspect that what you meant to write was:

char s[16] = "00004444eeeeffff";

which would have made s an array of 16 chars, containing the specified
list of character values.

Even if x actually did point at a structure, and even if you changed the
declaration of 's' as I suggest, neither x->b nor x->bb would contain
strings after the memcpy(). In C, a string is not a data type, but a
data structure: it is a series of bytes terminated with and including a
null character. You've done nothing to put a null character into either
x->b or x->bb. In your actual code, s[0] pointed at an array of 17
chars; the first 16 were the ones you specified, the 17th was the
terminating null character. In my suggested re-write, s does NOT contain
a string, because declaring it with a length of 16 leaves no room for
the terminating null character. This is permitted in C (it's an error in
C++).

You talk about reading a file, yet there's nothing about files in the
code you've provided. the basic tools you need when reading a binary
file into a structure are as follows:

FILE *infile;
// This defines 'infile' as pointer to a structure that contains
// information about the file you're reading, information that is
// needed by the <stdio.h> functions you'll be calling.

infile = fopen("filename.ext", "rb");
// This set infile to point at a structure that refers to the
// particular file named "filename.ext". The 'r' indicates read-only,
// the 'b' indicates "binary".

if(infile == NULL)
{
// Every function I'll be showing you can fail in ordinary
// circumstances. Always check for the possibility of failure, and
// decide how you want to deal with it.
}

test tim; // Defines an actual structure of your struct type.

// The following line reads in enough bytes from the file to fill tin.b:
if(fread(tin.b, sizeof tin.b, 1, infile) != 1)
{
// If fread() successfully reads in all of the memory you asked it
// to read, it returns the value of its second argument. Any other
// number indicates either an I/O error or the end of the file
if(ferror(infile))
{
// There was an I/O error. Take appropriate action
}
else if(feof(infile))
{
// fread() reached the end of the file before completing the
// read; take appropriate action.
}
}

// Now read in the contents of tin.bb. Even if there's padding between
// tin.b and tin.bb, by doing two separate reads you guarantee that
// each member will be correctly filled in.
if(fread(tin.bb, sizeof tin.bb, 1, infile) != 1)
{
// similar error handling
}

if(fclose(infile))
{
// Failure to close a input file is almost impossible, and should not
// cause any problems if it does occur, so there's no real need for
// this check.
// However, when you close an output file, a failure may indicate
// that the file was not correctly written, so always check for
// failure of fclose in that case.
}

You've got a great many things to learn before you can write a program
of this type. I recommend starting with something simpler, until you've
learned enough C to tackle a task of this complexity.
--
James Kuyper

Dennis Yurichev

unread,
Aug 20, 2012, 3:17:42 PM8/20/12
to
Also, do not forget about C compiler may align all struct members by 4
bytes on x86 and 8 bytes on Win64.
Since Windows PE file fields are all differently sized and this is very
important, please consult "pack" pragma:
http://msdn.microsoft.com/en-us/library/2e70t5y1(v=vs.80).aspx

Keith Thompson

unread,
Aug 20, 2012, 11:10:12 PM8/20/12
to
Dennis Yurichev <dennis_mai...@conus.info> writes:
[...]
> Also, do not forget about C compiler may align all struct members by 4
> bytes on x86 and 8 bytes on Win64.
> Since Windows PE file fields are all differently sized and this is very
> important, please consult "pack" pragma:
> http://msdn.microsoft.com/en-us/library/2e70t5y1(v=vs.80).aspx

A compiler is unlikely to align *all* struct members on 4-byte or 8-byte
boundaries. For example, given:

struct foo {
char x;
char y;
};

I'd expect offsetof(struct foo, y) to be 1 and sizeof (struct foo) to be
2 for most compilers.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Jorgen Grahn

unread,
Aug 20, 2012, 11:11:00 PM8/20/12
to
On Mon, 2012-08-20, Dennis Yurichev wrote:
> nwdpil <mke...@gmail.com> writes:
>
>> the ulimate goal is to read the MZ header from a binary windows pe
>> file, which is simple enough. anyway the theory goes (and this is the
>> bit i dont understand im new to c programming) i memcpy the data from
>> the file ACROSS a struct. is this possible?
...
>> typedef struct _test {
>> char b[8];
>> char bb[8];
>> }; test, *ptest;
>
> Also, do not forget about C compiler may align all struct members by 4
> bytes on x86 and 8 bytes on Win64.
> Since Windows PE file fields are all differently sized and this is very
> important, please consult "pack" pragma:
> http://msdn.microsoft.com/en-us/library/2e70t5y1(v=vs.80).aspx

Or skip the "map binary data to a struct" strategy and stick to
portable C, reading the MZ header octet by octet from an uint8_t
array. I find this much easier in the long run. For example, you
avoid endianness issues.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Reply all
Reply to author
Forward
0 new messages