The thread where casting is being discussed motivated me to try this. Let's
say you wanted to populate a BankRecord structure (as I defined below) with
17-character record numbers, but with the record numbers separated into a SSN
and an account number (and with a terminating '\0')...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char SSN[9];
char AccountNum[8];
char end;
} BankRecord;
int main( int argc, char * argv[] )
{
int i;
BankRecord *a;
if( argc < 2 ) {
printf( "No information provided\n" );
return EXIT_FAILURE;
}
if( (a=malloc((argc-1)*(sizeof(BankRecord)))) == NULL ) {
printf( "Malloc() failed\n" );
return EXIT_FAILURE;
}
for( i=1; i < argc; i++ ) {
snprintf( (char*)&a[i-1], sizeof(BankRecord), "%s", argv[i] );
}
for( i=0; i < argc-1; i++ ) {
printf( "%s\n", (char*)&a[i] ); /* just to prove that it works */
}
return EXIT_SUCCESS;
}
1) Is this code legal C? (it compiled with no warnings for me and worked
correctly)
2) Is the cast of a structure to a char* the best way to solve this contrived
problem?
3) How can I declare BankRecord in such a way so that end is a const char
equal to '\0'? Would that be desirable?
4) Any other comments?
--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org | 13 1906
Christopher Benson-Manica wrote: The thread where casting is being discussed motivated me to try this. Let's say you wanted to populate a BankRecord structure (as I defined below) with 17-character record numbers, but with the record numbers separated into a SSN and an account number (and with a terminating '\0')...
#include <stdio.h> #include <stdlib.h> #include <string.h>
typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
int main( int argc, char * argv[] ) { int i; BankRecord *a;
if( argc < 2 ) { printf( "No information provided\n" ); return EXIT_FAILURE; } if( (a=malloc((argc-1)*(sizeof(BankRecord)))) == NULL ) { printf( "Malloc() failed\n" ); return EXIT_FAILURE; } for( i=1; i < argc; i++ ) { snprintf( (char*)&a[i-1], sizeof(BankRecord), "%s", argv[i] ); } for( i=0; i < argc-1; i++ ) { printf( "%s\n", (char*)&a[i] ); /* just to prove that it works */ } return EXIT_SUCCESS; }
1) Is this code legal C? (it compiled with no warnings for me and worked correctly)
The code is "legal" in the sense that it exhibits no
undefined behavior (unless I've missed something). However,
it is not strictly conforming because it has implementation-
defined behavior: sizeof(BankRecord) is at least 18, but
might be larger because of padding within the struct. Thus,
the program's output when given a 20-character command-line
argument, say, depends on the details of the implementation.
In short: It is not guaranteed that the ninth input
character lands in the AccountNum[0] spot; it might instead
land in the limbo between SSN and AccountNum. The code
works, but might not be doing what you want.
2) Is the cast of a structure to a char* the best way to solve this contrived problem?
No, because it invokes the implementation-defined behavior
mentioned above and is thus not portable.
3) How can I declare BankRecord in such a way so that end is a const char equal to '\0'? Would that be desirable?
There's no way to achieve this with a declaration. Whether
that's a desirable state of affairs is a matter of taste -- if
you want C++ and constructors, you know where to find them.
4) Any other comments?
Yes: Write what you mean, not something else that you sort
of think might produce the same effect. If you've got two
distinct values -- SSN and AccountNum -- treat them as such.
If you want to view them as sub-fields of a single larger
string, declare a single 18-element array to contain that
single larger string.
A guess: Did you cut your teeth on FORTRAN, and perhaps
become overly fond of the EQUIVALENCE declaration? If so,
my recommendation is to lose that habit when writing C.
-- Er*********@sun.com
Christopher Benson-Manica wrote: The thread where casting is being discussed motivated me to try this. Let's say you wanted to populate a BankRecord structure (as I defined below) with 17-character record numbers, but with the record numbers separated into a SSN and an account number (and with a terminating '\0')...
#include <stdio.h> #include <stdlib.h> #include <string.h>
typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
int main( int argc, char * argv[] ) { int i; BankRecord *a;
if( argc < 2 ) { printf( "No information provided\n" ); return EXIT_FAILURE; } if( (a=malloc((argc-1)*(sizeof(BankRecord)))) == NULL ) { printf( "Malloc() failed\n" ); return EXIT_FAILURE; } for( i=1; i < argc; i++ ) { snprintf( (char*)&a[i-1], sizeof(BankRecord), "%s", argv[i] ); } for( i=0; i < argc-1; i++ ) { printf( "%s\n", (char*)&a[i] ); /* just to prove that it works */ } return EXIT_SUCCESS; }
1) Is this code legal C? (it compiled with no warnings for me and worked correctly)
Yep.
2) Is the cast of a structure to a char* the best way to solve this contrived problem?
You could use a union, but I don't think that would be better.
3) How can I declare BankRecord in such a way so that end is a const char equal to '\0'? Would that be desirable?
You can't. It would be desirable in a way, but I think it would create
a lot of complexities in the language that would quickly defeat its
desirability.
4) Any other comments?
I think if the argument passed is too long, the a[i-1] in the snprintf
call will end up null-less. I think maybe sscanf would be better because
you can specify the length in the format specifier and it will append a
null even if the entire length is used. Other than that I think its a
valid piece of code.
Matt Gregory
Christopher Benson-Manica wrote: The thread where casting is being discussed motivated me to try this. Let's say you wanted to populate a BankRecord structure (as I defined below) with 17-character record numbers, but with the record numbers separated into a SSN and an account number (and with a terminating '\0')...
#include <stdio.h> #include <stdlib.h> #include <string.h>
typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
int main( int argc, char * argv[] ) { int i; BankRecord *a;
if( argc < 2 ) { printf( "No information provided\n" ); return EXIT_FAILURE; } if( (a=malloc((argc-1)*(sizeof(BankRecord)))) == NULL ) { printf( "Malloc() failed\n" ); return EXIT_FAILURE; } for( i=1; i < argc; i++ ) { snprintf( (char*)&a[i-1], sizeof(BankRecord), "%s", argv[i] ); } for( i=0; i < argc-1; i++ ) { printf( "%s\n", (char*)&a[i] ); /* just to prove that it works */
You should try another test:
printf("AccountNum = %s\n",a[i].Accountum);
and see if it still works as expected.
} return EXIT_SUCCESS; }
1) Is this code legal C? (it compiled with no warnings for me and worked correctly) 2) Is the cast of a structure to a char* the best way to solve this contrived problem?
No, You have issues of struct member padding which are address in
fag questions 2.13 and 2.12 http://www.eskimo.com/~scs/C-faq/q2.13.html http://www.eskimo.com/~scs/C-faq/q2.12.html
--
Al Bowers
Tampa, Fl USA
mailto: xa*@abowers.combase.com (remove the x) http://www.geocities.com/abowers822/
Eric Sosman wrote: Christopher Benson-Manica wrote: [...] typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
[...]
In short: It is not guaranteed that the ninth input character lands in the AccountNum[0] spot; it might instead land in the limbo between SSN and AccountNum.
Um, er, "Oops." The ninth input character necessarily
lands in SSN[8]; it's the *tenth* character whose location
is uncertain. Sorry about that.
-- Er*********@sun.com
Matt Gregory <ms********@earthlink.net> spoke thus: You can't. It would be desirable in a way, but I think it would create a lot of complexities in the language that would quickly defeat its desirability.
Just making sure, thanks :)
I think if the argument passed is too long, the a[i-1] in the snprintf call will end up null-less. I think maybe sscanf would be better because you can specify the length in the format specifier and it will append a null even if the entire length is used. Other than that I think its a valid piece of code.
According to my documentation for snprintf(), it writes size-1 characters and
the size-th character is guaranteed to be '\0', so if sizeof(BankRecord) is
18, I'm fine. Of course, as the previous reply noted, that isn't guaranteed
to be the case...
--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Eric Sosman <Er*********@sun.com> spoke thus: Um, er, "Oops." The ninth input character necessarily lands in SSN[8]; it's the *tenth* character whose location is uncertain. Sorry about that.
So structure fields are not guaranteed to be contiguous? How unfortunate :(
--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Christopher Benson-Manica <at***@nospam.cyberspace.org> scribbled the following: Eric Sosman <Er*********@sun.com> spoke thus: Um, er, "Oops." The ninth input character necessarily lands in SSN[8]; it's the *tenth* character whose location is uncertain. Sorry about that.
So structure fields are not guaranteed to be contiguous? How unfortunate :(
No, they aren't. The implementation is free to add any padding it likes
between any two members, or after the last member. The first member
MUST begin at offset 0, though.
--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"That's no raisin - it's an ALIEN!"
- Tourist in MTV's Oddities
Eric Sosman wrote: Christopher Benson-Manica wrote:
1) Is this code legal C? (it compiled with no warnings for me and worked correctly)
The code is "legal" in the sense that it exhibits no undefined behavior (unless I've missed something). However, it is not strictly conforming because it has implementation- defined behavior: sizeof(BankRecord) is at least 18, but might be larger because of padding within the struct. Thus, the program's output when given a 20-character command-line argument, say, depends on the details of the implementation.
Oh, I forgot about that. Oops. This is the very thing that
drove me nuts the first time I tried to translate a Pascal
program to C which wrote records to disk by calling Write().
Damn. Never did get that debugged. Had to switch back to
Pascal.
Matt Gregory
Joona I Palaste wrote: Christopher Benson-Manica <at***@nospam.cyberspace.org> scribbled the following: Eric Sosman <Er*********@sun.com> spoke thus: Um, er, "Oops." The ninth input character necessarily lands in SSN[8]; it's the *tenth* character whose location is uncertain. Sorry about that.
So structure fields are not guaranteed to be contiguous? How unfortunate :(
No, they aren't. The implementation is free to add any padding it likes between any two members, or after the last member. The first member MUST begin at offset 0, though.
The case for padding in structures is for alignment of multibyte
objects, int, long, double, etc. The char is a single-byte object. It
can appear anywhere and has no known alignment requirements, even as an
array. There need be no padding between char objects. I betcha... sizeof
(BankRecord) == 18 on every implementation we have.
--
Joe Wright mailto:jo********@earthlink.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Joe Wright <jo********@earthlink.net> scribbled the following: Joona I Palaste wrote: Christopher Benson-Manica <at***@nospam.cyberspace.org> scribbled the following: > Eric Sosman <Er*********@sun.com> spoke thus: >> Um, er, "Oops." The ninth input character necessarily >> lands in SSN[8]; it's the *tenth* character whose location >> is uncertain. Sorry about that.
> So structure fields are not guaranteed to be contiguous? How unfortunate :(
No, they aren't. The implementation is free to add any padding it likes between any two members, or after the last member. The first member MUST begin at offset 0, though. The case for padding in structures is for alignment of multibyte objects, int, long, double, etc. The char is a single-byte object. It can appear anywhere and has no known alignment requirements, even as an array. There need be no padding between char objects. I betcha... sizeof (BankRecord) == 18 on every implementation we have.
As long as "anywhere" means "anywhere after the first member", that is
true. There need be no padding between char objects, but there CAN be.
Arrays, OTOH, are required to be contiguous and padding-free.
--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"He said: 'I'm not Elvis'. Who else but Elvis could have said that?"
- ALF
In message <3F***********@earthlink.net>
Joe Wright <jo********@earthlink.net> wrote: typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
The case for padding in structures is for alignment of multibyte objects, int, long, double, etc. The char is a single-byte object. It can appear anywhere and has no known alignment requirements, even as an array. There need be no padding between char objects. I betcha... sizeof (BankRecord) == 18 on every implementation we have.
My most commonly used platform, which is ARM-based, has
sizeof(BankRecord) == 20, as all aggregate types are a whole number of 32-bit
words, and 32-bit aligned. This makes life easier when doing structure
assignments and initialisation, as it can use "load/store multiple word"
instructions, which only access word-aligned and sized data.
This may be atypical, but it suits the target architecture, and the C
standard is thankfully designed to allow implementations to make choices like
this.
The only pitfall is the usual one of programmers assuming, like you, details
of the structure padding. One example is the BSD <arpa/tftp.h> header file
which contains:
struct tftphdr {
short tur_opcode; /* TFTP opcode */
/******** OOPS - 2 bytes of unexpected padding here *******/
union {
struct {
char tur_stuff[1]; /* RRQ/WRQ/OACK params */
} tu_rq;
struct {
short tud_block; /* block# or error code */
char tud_data[1]; /* data or error string */
} tu_data;
} th_u;
}; /* sizeof(struct tftphdr) == 8 */
--
Kevin Bracey, Principal Software Engineer
Tematic Ltd Tel: +44 (0) 1223 503464
182-190 Newmarket Road Fax: +44 (0) 1223 503458
Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/
Kevin Bracey wrote: In message <3F***********@earthlink.net> Joe Wright <jo********@earthlink.net> wrote:
typedef struct { char SSN[9]; char AccountNum[8]; char end; } BankRecord;
The case for padding in structures is for alignment of multibyte objects, int, long, double, etc. The char is a single-byte object. It can appear anywhere and has no known alignment requirements, even as an array. There need be no padding between char objects. I betcha... sizeof (BankRecord) == 18 on every implementation we have.
My most commonly used platform, which is ARM-based, has sizeof(BankRecord) == 20, as all aggregate types are a whole number of 32-bit words, and 32-bit aligned. This makes life easier when doing structure assignments and initialisation, as it can use "load/store multiple word" instructions, which only access word-aligned and sized data.
This may be atypical, but it suits the target architecture, and the C standard is thankfully designed to allow implementations to make choices like this.
The only pitfall is the usual one of programmers assuming, like you, details of the structure padding. One example is the BSD <arpa/tftp.h> header file which contains:
struct tftphdr { short tur_opcode; /* TFTP opcode */ /******** OOPS - 2 bytes of unexpected padding here *******/ union { struct { char tur_stuff[1]; /* RRQ/WRQ/OACK params */ } tu_rq; struct { short tud_block; /* block# or error code */ char tud_data[1]; /* data or error string */ } tu_data; } th_u; }; /* sizeof(struct tftphdr) == 8 */
You are, of course, correct. My unthoughtful assumption that the world
is like Intel or SPARC coerces me to commit these errors. I am truly
sorry.
--
Joe Wright mailto:jo********@earthlink.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein --- This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Brian Blais |
last post by:
Hello,
I saw on a couple of recent posts people saying that casting the return
value of malloc is bad, like:
d=(double *) malloc(50*sizeof(double));
why is this bad? I had always thought...
|
by: Ramesh Tharma |
last post by:
Hi,
Is any one knows what's wrong with the following code, I was told that it
will compile and run but it will crash for some values.
Assume that variables are initilized.
char* c;
long*...
|
by: c |
last post by:
Hello All,
I am struggling with simple casting issue within c# and would really
appreciate some insight into where I am going wrong.
I have two classes, ClassA and ClassB. Each implements a...
|
by: Mark P |
last post by:
A colleague asked me something along the lines of the following today.
For some type X he has:
X* px = new X;
Then he wants to convert px to a char* (I'm guessing for the purpose of...
|
by: brekehan |
last post by:
I've always been a little sketchy on the differences between static,
dynamic, and reinterpret casting. I am looking to clean up the
following block by using C++ casting instead of the C style...
|
by: johanatan |
last post by:
Does anyone know the reasons for the lack of an implicit casting
operator in any greater depth than:
A. Automatic conversion is believed to be too error prone.
(from the FAQ at the bottom of:...
|
by: Taras_96 |
last post by:
Hi everyone,
I was experimenting with static_cast and reinterpret cast
#include <iostream>
struct A1 { int a; };
struct A2 { double d; };
struct B : public A1, A2
|
by: jason.cipriani |
last post by:
There have been some recent threads about casting pointers to and from
void* that have me rethinking some of my usual practices. I have a
couple of questions.
1. What is the purpose of C++'s...
|
by: =?Utf-8?B?WWFua2VlIEltcGVyaWFsaXN0IERvZw==?= |
last post by:
I'm doing my c# more and more like i used to code c++, meaning i'm casting
more often than creating an instance of objects.
like :
protected void gvOrderDetailsRowDataBound(object sender,...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
| |