pointer to a structure (simple question for a real C programmer)
Author |
Message |
g.. #1 / 17
|
 pointer to a structure (simple question for a real C programmer)
I am a long time mainframe assembler programmer that is struggling with what is probably a simple issue. I have a C program that is called by an assembler program. The assembler program passes an address of a piece of storage to the C program. The storage contains a variety of fields. I want to be able to access one of those fields in the C program. It is a fullword binary field. I know I need a struct. My problem is getting addressablity to the struct. Program snippets follow: ******************************************************************** <snip> typedef struct jrbdsub_type{ char jrbdsub_subcode[4]; char jrbdsub_filler[44]; int jrbdsub_suberrno; Quote: } jrbdsub;
<snip> int main(int argc, char **argv) <snip> struct jrbdsub_type *st_ptr; <snip> subptr = (int) argv[5]; <snip> st_ptr = (jrbdsub*) subptr; if (st_ptr->jrbdsub_subcode=='SUB ') { printf( "found the subcode\n"); Quote: }
******************************************************************** When I compile the C program I receive: CBC3076 Character constant 'SUB ' has more than one character. No more than rightmost 4 characters are used. CBC3068 Operation between types "unsigned char*" and "int" is not allowed. I know that subptr contains a good pointer to the storage (because an assembler program I call later can use it successfully). 1) am I loading the st_ptr correctly in order to get addressability to jrbdsub? 2) How can I get rid of the compile errors. 3) How many other ways am I screwing this up? Thanks very much.
|
Mon, 10 Oct 2005 02:59:21 GMT |
|
 |
Jens.Toerr.. #2 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> I am a long time mainframe assembler programmer that is struggling > with what is probably a simple issue. > I have a C program that is called by an assembler program. The > assembler program passes an address of a piece of storage to the C > program. > The storage contains a variety of fields. I want to be able to access > one of those fields in the C program. It is a fullword binary field. > I know I need a struct. My problem is getting addressablity to the > struct. > Program snippets follow: > ******************************************************************** > <snip> > typedef struct jrbdsub_type{ > char jrbdsub_subcode[4]; > char jrbdsub_filler[44]; > int jrbdsub_suberrno; > } jrbdsub; > <snip> > int main(int argc, char **argv) > <snip> > struct jrbdsub_type *st_ptr; > <snip> > subptr = (int) argv[5];
argv[5] isn't a value but a string (if it exists). A C program gets a number (argc) of strings (i.e char arrays, with a 0 as the last element) as its arguments. You will have convert it back to the type you need before you can use it. Just casting won't help you, if you pass a program e.g. "534" on the command line, the program will get a string (i.e. an char array containing the characters '5', '3', '4' and '\0') and not an int with a value of 534. But in this case I doubt that it will work at all if you want to pass your program an address belonging to a different program unless you are working on a system where each process can access the memory of all other processes (and it's getting quite off-topic for c.l.c. since standard C does not know about the mere existence of more than one process). Under normal modern OSes each process has its own memory space and an address passed to it from another process will mean nothing to the program... And even if this works because your system allows it, the layout of the structure may look quite different from what you expect. The compiler can insert as many padding bytes between the elements of the structure as it thinks necessary or prudent (and a different compiler is allowed to have different opinions). This would be one of the cases where you wouldn't use a structure directly but do the unpacking manually byte by byte and the push the extracted data into a structure. Quote: > <snip> > st_ptr = (jrbdsub*) subptr; > if (st_ptr->jrbdsub_subcode=='SUB ')
You can't compare strings in C using '==' (and 'SUB ' isn't be a string anyway, you would need "SUB ", i.e. in double quotes), with '==' you compare if the address stored in 'st_ptr->jrbdsub_subcode' is identical to the address 'SUB '. But since 'SUB ' isn't a pointer but is treated as an int, you get your compiler warning. If you want to compare strings you need the function strcmp(), and strncmp() if you want to compare only some parts of two strings. And here you will need strncmp() because 'st_ptr->jrbdsub_subcode' can't hold the string "SUB ", this string requires 5 chars (a string must always end in a '\0' character. So you must restrict the comparison to the first four bytes anyway, strcmp() will only stop when it finds a '\0' in one of the strings and thus would compare past the end of what's stored in 'st_ptr->jrbdsub_subcode'. Regards, Jens -- _ _____ _____
_ | | | | | | | |_| | | | | | http://www.physik.fu-berlin.de/~toerring \___/ens|_|homs|_|oerring
|
Mon, 10 Oct 2005 04:17:12 GMT |
|
 |
Default Use #3 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> typedef struct jrbdsub_type{ > char jrbdsub_subcode[4]; > char jrbdsub_filler[44]; > int jrbdsub_suberrno; > } jrbdsub; > if (st_ptr->jrbdsub_subcode=='SUB ') > When I compile the C program I receive: > CBC3076 Character constant 'SUB ' has more than one character. No more > than rightmost 4 characters are used. > CBC3068 Operation between types "unsigned char*" and "int" is not > allowed.
1. String literals in C are defined using full quote (") delimiters. To define the string, use "SUB ". 2. You can't compare arrays with the == operator. For strings, use the strcmp() function. 3. Get a good book on C and read it through before trying to write any code. Brian Rodenborn
|
Mon, 10 Oct 2005 04:04:04 GMT |
|
 |
Eric Sosma #4 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > typedef struct jrbdsub_type{ > > char jrbdsub_subcode[4]; > > char jrbdsub_filler[44]; > > int jrbdsub_suberrno; > > } jrbdsub; > > if (st_ptr->jrbdsub_subcode=='SUB ') > > When I compile the C program I receive: > > CBC3076 Character constant 'SUB ' has more than one character. No more > > than rightmost 4 characters are used. > > CBC3068 Operation between types "unsigned char*" and "int" is not > > allowed. > 1. String literals in C are defined using full quote (") delimiters. To > define the string, use "SUB ". > 2. You can't compare arrays with the == operator. For strings, use the > strcmp() function.
I suspect strcmp() won't work here. `jrbdsub_subcode' is a four-character array and is apparently expected to hold the four characters 'S','U','B',' ' -- and that isn't a "string" as defined by the C library because it lacks the terminating '\0' byte. strcmp() requires two properly- formed strings, and trying to use it on a non-string array invites disaster. To compare two arbitrary four-byte arrays (not necessarily "strings"), use the memcmp() function: if (memcmp(st_ptr->jrbdsub_subcode, "SUB ", 4) == 0) ... (The literal "SUB " actually creates a properly-terminated string, a five-byte array containing 'S','U','B',' ','\0'. But the final '\0' won't confuse memcmp(), because it's been told to inspect only the first four characters of each array.) --
|
Mon, 10 Oct 2005 05:06:52 GMT |
|
 |
Default Use #5 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > 2. You can't compare arrays with the == operator. For strings, use the > > strcmp() function. > I suspect strcmp() won't work here. `jrbdsub_subcode' > is a four-character array and is apparently expected to hold > the four characters 'S','U','B',' ' -
Good pickup. Quote: > To compare two arbitrary four-byte arrays (not necessarily > "strings"), use the memcmp() function:
Or strncmp(). Brian Rodenborn
|
Mon, 10 Oct 2005 07:10:21 GMT |
|
 |
Eric Sosma #6 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > > 2. You can't compare arrays with the == operator. For strings, use the > > > strcmp() function. > > I suspect strcmp() won't work here. `jrbdsub_subcode' > > is a four-character array and is apparently expected to hold > > the four characters 'S','U','B',' ' - > Good pickup. > > To compare two arbitrary four-byte arrays (not necessarily > > "strings"), use the memcmp() function: > Or strncmp().
strncmp() would work in this case, but is not the right choice for general N-byte arrays which might contain embedded zero bytes. I'd suggest memcmp() even for the O.P.'s case (where embedded zeroes seem not to be an issue), simply because it's, well, simpler. --
|
Mon, 10 Oct 2005 22:20:51 GMT |
|
 |
CBFalcone #7 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
... snip ... > > > To compare two arbitrary four-byte arrays (not necessarily > > > "strings"), use the memcmp() function: > > Or strncmp(). > strncmp() would work in this case, but is not the > right choice for general N-byte arrays which might > contain embedded zero bytes. I'd suggest memcmp() even > for the O.P.'s case (where embedded zeroes seem not to > be an issue), simply because it's, well, simpler.
No, strncmp won't work. It stops on the first '\0'. N869: 7.21.4.4 The strncmp function Synopsis [#1] #include <string.h> int strncmp(const char *s1, const char *s2, size_t n); Description [#2] The strncmp function compares not more than n characters (characters that follow a null character are not <-- compared) from the array pointed to by s1 to the array pointed to by s2. Returns [#3] The strncmp function returns an integer greater than, equal to, or less than zero, accordingly as the possibly null-terminated array pointed to by s1 is greater than, equal to, or less than the possibly null-terminated array pointed to by s2. --
Available for consulting/temporary embedded and systems. <http://cbfalconer.home.att.net> USE worldnet address!
|
Mon, 10 Oct 2005 23:13:41 GMT |
|
 |
g.. #8 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > > typedef struct jrbdsub_type{ > > > char jrbdsub_subcode[4]; > > > char jrbdsub_filler[44]; > > > int jrbdsub_suberrno; > > > } jrbdsub; > > > if (st_ptr->jrbdsub_subcode=='SUB ') > > > When I compile the C program I receive: > > > CBC3076 Character constant 'SUB ' has more than one character. No more > > > than rightmost 4 characters are used. > > > CBC3068 Operation between types "unsigned char*" and "int" is not > > > allowed. > > 1. String literals in C are defined using full quote (") delimiters. To > > define the string, use "SUB ". > > 2. You can't compare arrays with the == operator. For strings, use the > > strcmp() function. > I suspect strcmp() won't work here. `jrbdsub_subcode' > is a four-character array and is apparently expected to hold > the four characters 'S','U','B',' ' -- and that isn't a > "string" as defined by the C library because it lacks the > terminating '\0' byte. strcmp() requires two properly- > formed strings, and trying to use it on a non-string array > invites disaster. > To compare two arbitrary four-byte arrays (not necessarily > "strings"), use the memcmp() function: > if (memcmp(st_ptr->jrbdsub_subcode, "SUB ", 4) == 0) > ... > (The literal "SUB " actually creates a properly-terminated > string, a five-byte array containing 'S','U','B',' ','\0'. > But the final '\0' won't confuse memcmp(), because it's been > told to inspect only the first four characters of each array.)
Thanks to all who responded for your answers as well as your patience.
|
Mon, 10 Oct 2005 23:46:15 GMT |
|
 |
Default Use #9 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> strncmp() would work in this case, but is not the > right choice for general N-byte arrays which might > contain embedded zero bytes. I'd suggest memcmp() even > for the O.P.'s case (where embedded zeroes seem not to > be an issue), simply because it's, well, simpler.
That doesn't make any sense. He's comparing to a string literal, how could embedded 0 characters come into play? Brian Rodenborn
|
Tue, 11 Oct 2005 00:17:08 GMT |
|
 |
Default Use #10 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> No, strncmp won't work. It stops on the first '\0'. N869:
What's your point? He's comparing a character buffer to a string literal. You WANT it to stop at the first '\0'. Brian Rodenborn
|
Tue, 11 Oct 2005 00:18:14 GMT |
|
 |
Eric Sosma #11 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > strncmp() would work in this case, but is not the > > right choice for general N-byte arrays which might > > contain embedded zero bytes. I'd suggest memcmp() even > > for the O.P.'s case (where embedded zeroes seem not to > > be an issue), simply because it's, well, simpler. > That doesn't make any sense. He's comparing to a string literal, how > could embedded 0 characters come into play?
CBF also seemed to have trouble understanding what I wrote, so on the "Everybody's out of step except Johnny" principle I guess I must have mis-written. Here are the points I was trying to make: 1) The O.P.'s data is a four-character array, and he's trying to find out whether those four characters are 'S','U','B',' '. 2) The four-character array lacks a terminating '\0' and hence is not a string, so strcmp() is out. 3) If the array actually contains 'S','U','B',' ' either memcmp() or strncmp() against the first four bytes of the five-byte string "SUB " will detect the match. 4) If the array actually contains something else, either memcmp() or strncmp() will detect the mismatch. 5) But (4) only holds because 'S','U','B',' ' has no embedded zero bytes. 6) In the more general case where the key value could contain embedded zeroes, memcmp() would always deliver the correct answer but strncmp() could be fooled. For example, if the test value were 'A',0,'B',1 (note the un-quoted digits) and the array held 'A',0,'X',42 strncmp() would report a match because it would inspect only the first two characters. 7) Since the O.P. is unfamiliar with C's world-view I didn't want him to get the notion that strncmp() was the preferred way to compare arbitrary chunks of memory. strncmp() can handle non-strings, yes, but it still has string-ish behavior. 8) Therefore I recommended memcmp(). --
|
Tue, 11 Oct 2005 01:16:00 GMT |
|
 |
Dan P #12 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
>... snip ... >> > > To compare two arbitrary four-byte arrays (not necessarily >> > > "strings"), use the memcmp() function: >> > Or strncmp(). >> strncmp() would work in this case, but is not the >> right choice for general N-byte arrays which might >> contain embedded zero bytes. I'd suggest memcmp() even >> for the O.P.'s case (where embedded zeroes seem not to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Quote: >> be an issue), simply because it's, well, simpler. > ^^^^^^^^^^^^ >No, strncmp won't work. It stops on the first '\0'. N869:
Have I ever told you to engage your brain before posting? ;-) Dan -- Dan Pop DESY Zeuthen, RZ group
|
Tue, 11 Oct 2005 01:19:55 GMT |
|
 |
Default Use #13 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> 7) Since the O.P. is unfamiliar with C's world-view > I didn't want him to get the notion that strncmp() > was the preferred way to compare arbitrary chunks > of memory. strncmp() can handle non-strings, yes, > but it still has string-ish behavior.
Horses for courses. I was addressing the given case, which did not have two arbitrary buffers. Indeed, two character buffers, which may have embedded '\0' characters, and for which you want to compare each byte, cries out for memcmp(). However, that doesn't mean it's appropriate for every case. Here, you have a character buffer compared to a string literal (I've assumed that was the OP's intent anyway). Here we have a very "string-ish" situation, as you put it above. You can write the test as: strncmp (buf, "the literal", sizeof buf); This has certain value for the problem. You can't run off the end of buf, because of sizeof, and you can't run off the end of the literal since strncmp() will terminate when it hits the '\0' character. Naturally though, it requires buf to be an actual array in that scope, not a character pointer. As a struct member, that's not a problem IN THIS CASE. For the general problem of two character buffers that aren't necessarily strings, the size of each buffer will have to be calculated first, as there is no other way to do memcmp() safely. As in: if (sizeof buf1 != sizeof buf2) { /* obviously can't match report failure */ Quote: }
else if (memcmp (buf1, buf2, sizeof buf1) != 0) { /* report failure */ Quote: }
else { /* report success */ Quote: }
However, I think my third point was the most important one, which is that the OP needs to learn C and not hack around in it. It's just not a good language for trying to slap some code together. It'll figure out a way to getcha. Brian Rodenborn
|
Tue, 11 Oct 2005 02:41:53 GMT |
|
 |
Jeremy Yallo #14 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> For the general problem of two character buffers that aren't necessarily > strings, the size of each buffer will have to be calculated first, as > there is no other way to do memcmp() safely. As in: > if (sizeof buf1 != sizeof buf2) > { > /* obviously can't match report failure */ > }
If you know at compile-time that the buffer sizes differ there's no reason to wait until runtime to report the mismatch. Jeremy.
|
Tue, 11 Oct 2005 04:05:18 GMT |
|
 |
Default Use #15 / 17
|
 pointer to a structure (simple question for a real C programmer)
Quote:
> > For the general problem of two character buffers that aren't necessarily > > strings, the size of each buffer will have to be calculated first, as > > there is no other way to do memcmp() safely. As in: > > if (sizeof buf1 != sizeof buf2) > > { > > /* obviously can't match report failure */ > > } > If you know at compile-time that the buffer sizes differ there's no > reason to wait until runtime to report the mismatch.
What did you have in mind, specifically? Brian Rodenborn
|
Tue, 11 Oct 2005 05:02:38 GMT |
|
|
Page 1 of 2
|
[ 17 post ] |
|
Go to page:
[1]
[2] |
|