What is wrong with this code? | | |
#define MAX_VALUES 64
typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
VALUES_STRUCT values_struct=
{3,0,0.0,0.0,0.0,{{1,1.0,1.0,1.0},{1,1.0,1.0,1.0}, {1,1.0,1.0,1.0}}};
double add_double_numbers
(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
return total;
}
void add_value_4(void) {
values_struct.tot_value_4=add_double_numbers
(&values_struct.values[0].value_4,values_struct.num_values,
sizeof(VALUES));
printf("\nThe total is %f",values_struct.tot_value_4);
}
int main(void) {
add_value_4();
return 0;
}
---
William Ernest Reid | | | | re: What is wrong with this code?
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote: Quote:
>#define MAX_VALUES 64
You fail to include <stdio.h>, which would affect the interpretation
of printf(), possibly causing garbage values to be printed out.
Other than that: what is the difference between the output you
see and the output you expect?
--
There are some ideas so wrong that only a very intelligent person
could believe in them. -- George Orwell | | | | re: What is wrong with this code?
Bill Reid wrote:
Why do you think there's something wrong with it? Did it fail to
compile? Did it get different results than you expected?
Brian | | | | re: What is wrong with this code?
Walter Roberson <roberson@ibd.nrc-cnrc.gc.cawrote in message
news:f27kud$50$1@canopus.cc.umanitoba.ca... Quote:
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote:
>
You fail to include <stdio.h>, which would affect the interpretation
of printf(), possibly causing garbage values to be printed out.
>
Uh, yeah, for me on this compiler, just a warning, I think. I haven't
actually compiled the actual code I posted, just similar stuff... Quote:
Other than that: what is the difference between the output you
see and the output you expect?
I get exactly what I expect. Honestly, I was looking for some
type of criticism of the general approach for accessing structure
elements in add_double_numbers(), that's all. Quote:
There are some ideas so wrong that only a very intelligent person
could believe in them. -- George Orwell
That is precisely the point, that is precisely the point. Here, let's
try again...what is wrong with this code?
#include <stdio.h /* !!!!!!!!!!!! */
#define MAX_VALUES 64
typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
VALUES_STRUCT values_struct=
{3,0,0.0,0.0,0.0,{{1,1.0,1.0,1.0},{1,1.0,1.0,1.0}, {1,1.0,1.0,1.0}}};
double add_double_numbers
(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
return total;
}
void add_value_4(void) {
values_struct.tot_value_4=add_double_numbers
(&values_struct.values[0].value_4,values_struct.num_values,
sizeof(VALUES));
printf("\nThe total is %f",values_struct.tot_value_4);
}
int main(void) {
add_value_4();
return 0;
}
---
William Ernest Reid | | | | re: What is wrong with this code?
Bill Reid said: Quote:
>
Walter Roberson <roberson@ibd.nrc-cnrc.gc.cawrote in message
news:f27kud$50$1@canopus.cc.umanitoba.ca... Quote:
>In article
><3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>, Bill
>Reid <hormelfree@happyhealthy.netwrote:
>>
>You fail to include <stdio.h>, which would affect the interpretation
>of printf(), possibly causing garbage values to be printed out.
>>
Uh, yeah, for me on this compiler, just a warning, I think.
No such thing. It's not "just a warning". It's a warning. Quote:
I haven't
actually compiled the actual code I posted, just similar stuff...
....removing the last vestiges of a point from this entire thread.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at the above domain, - www. | | | | re: What is wrong with this code?
In article <bCK1i.144938$VU4.58740@bgtnsc05-news.ops.worldnet.att.net>
Bill Reid <hormelfree@happyhealthy.netwrote: Quote:
>I get exactly what I expect. Honestly, I was looking for some
>type of criticism of the general approach for accessing structure
>elements in add_double_numbers(), that's all.
[where the add_double_numbers routine is] Quote:
>double add_double_numbers
>(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
>
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
>
return total;
}
Oh ... in that case, as far as I can tell, the code is valid. It
does seem "slightly dangerous" (in the sense that it would be easy
for a caller to provide improper arguments, and then have everything
go kaboom). Also, while we tend to discourage casts in comp.lang.c,
I would probably go ahead and use them here, and make a few other
minor changes:
/*
* Iterate over some kind of array, which may be an array of structures
* or array of arrays, in which there is at least one "double" element.
* Add up the n "double" elements that are spaced apart by
* "inc_size" bytes, given a pointer to the first such "double".
*/
double add_double_numbers(double *first, size_t n, size_t inc_size) {
unsigned char *p; /* will point to our various "double"s */
double total = 0.0;
size_t i;
p = (unsigned char *)first;
for (i = 0; i < n; i++) {
total += *(double *)p;
p += inc_size;
}
return total;
}
The loop could be compressed to:
for (p = (unsigned char *)first, i = 0; i < n; p += inc_size, i++)
total += *(double *)p;
for those who prefer to see all the loop invariants in the "for"
expressions.
The reason for taking a "double *" is to force the caller to
pass the address of the first "double" element in the array of
structures, in case the caller wants to do something like:
struct S {
int a;
double x;
char *b;
FILE *c;
/* etc */
};
struct S arr[SIZE];
double result;
...
result = add_double_numbers(<args here to total up "arr">);
which in this case should be:
result = add_double_numbers(&arr[0].x, SIZE, sizeof arr[0]);
and *not*:
result = add_double_numbers(&arr[0], SIZE, sizeof arr[0]); /*WRONG*/
(Note that you could actually make the latter work by passing not
only a "byte spacing from double to double", i.e., inc_size, but
also an "offset from base to first double" element. There is
no real need, in this case: we can just include the offset in
the first argument. Some might like the symmetry of &arr[0] and
sizeof arr[0], though, in which case, add one more argument,
offsetof(arr[0], x), and change the first formal parameter to
"void *base" and make the other obvious required changes.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers. | | | | re: What is wrong with this code?
"Bill Reid" <hormelfree@happyhealthy.netwrites: Quote:
Walter Roberson <roberson@ibd.nrc-cnrc.gc.cawrote in message
news:f27kud$50$1@canopus.cc.umanitoba.ca... Quote:
>In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
>Bill Reid <hormelfree@happyhealthy.netwrote:
>>
>You fail to include <stdio.h>, which would affect the interpretation
>of printf(), possibly causing garbage values to be printed out.
>>
Uh, yeah, for me on this compiler, just a warning, I think.
If you use functions declared in <stdio.h>, the "#include <stdio.h>"
directive is not optional. Your compiler might not do you the favor
of rejecting your program, but you need to add it anyway.
(There are some cases where the "#include" isn't actually mandatory as
far as the language standard is concerned, but there is no reason at
all not to add it.) Quote:
I haven't
actually compiled the actual code I posted, just similar stuff...
[...]
Well, if it's not worth your time to compile your code before posting
it, it's certainly not worth my time to look at it. Let us know when
you have a serious question. Quote:
I get exactly what I expect. Honestly, I was looking for some
type of criticism of the general approach for accessing structure
elements in add_double_numbers(), that's all.
Then it would have been useful to say so. Asking "What is wrong with
this code?" (and that only in the subject header; it needs to be in
the body of your article) isn't particularly helpful.
We're glad to answer questions, but you need to take the time to ask
them.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister" | | | | re: What is wrong with this code?
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote: Quote:
>typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
>
>typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
To avoid replicating the fields here, you could do
typedef struct {
unsigned num_values;
VALUES total[MAX_VALUES];
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
and refer to v.total.value1 instead of v.tot_value_1, etc. Quote:
>double add_double_numbers
>(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
>
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
>
return total;
}
I would prefer something like:
double add_double_numbers(double *base, size_t count, size_t stride)
{
unsigned char *byte_ptr = (unsigned char *)base;
unsigned i;
double total=0.0;
for(i=0; i<count; i++)
{
total += *(double *)byte_ptr;
byte_ptr += stride;
}
return total;
}
Since the function only works for doubles, you gain nothing by making
the argument void *; use double * to emphasise its meaning.
size_t is the right type for object counts and sizes (cf calloc()).
I prefer my variable names; others may disagree. ("Stride" is a
standard term for this sort of distance between successive elements.)
There's no need to use both void and char pointers; converting a
correctly aligned pointer to and from a char pointer is guaranteed to
work. "Char" would be just as correct as "unsigned char" but the
latter is perhaps better for generic byte pointers.
Using a cast in the accumulating expression instead of an extra
variable and assignment might not be to everyone's taste, but reducing
the vertical size of a function aids readability in my opinion.
When a loop is over a sequence of integers, a for loop is clearer than
a while loop.
-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963. | | | | re: What is wrong with this code?
In article <f280o9$g5l$2@pc-news.cogsci.ed.ac.uk>, I wrote: Quote:
>double add_double_numbers(double *base, size_t count, size_t stride)
>{
unsigned char *byte_ptr = (unsigned char *)base;
unsigned i;
That should have been "size_t i;".
-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963. | | | | re: What is wrong with this code?
Chris Torek <nospam@torek.netwrote in message
news:f27up702nh2@news5.newsguy.com... Quote:
In article <bCK1i.144938$VU4.58740@bgtnsc05-news.ops.worldnet.att.net>
Bill Reid <hormelfree@happyhealthy.netwrote:
Quote: Quote:
I get exactly what I expect. Honestly, I was looking for some
type of criticism of the general approach for accessing structure
elements in add_double_numbers(), that's all.
>
[where the add_double_numbers routine is]
> Quote:
double add_double_numbers
(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
return total;
}
>
Oh ... in that case, as far as I can tell, the code is valid. It
does seem "slightly dangerous" (in the sense that it would be easy
for a caller to provide improper arguments, and then have everything
go kaboom).
Yes, but I tend to use stuff like this in my REALLY fundamental
"deep" libraries, and usually the only stuff that touches it are essentially
slightly higher-level more specific-purpose libraries. I'm trading off
a little "danger" for shrinking my total code-base by eliminating as
much redundant (except for the function signature) simplistic functionality
as possible... Quote:
Also, while we tend to discourage casts in comp.lang.c,
I would probably go ahead and use them here, and make a few other
minor changes:
>
OK, THIS is what I'm looking for, an ACTUAL discussion of
real-world practical "standard C" here... Quote:
/*
* Iterate over some kind of array, which may be an array of structures
* or array of arrays, in which there is at least one "double" element.
* Add up the n "double" elements that are spaced apart by
* "inc_size" bytes, given a pointer to the first such "double".
*/
Yup, that's it in a nutshell, except I use this basic approach for
integers, long doubles, chars, whatever (the classic and most
straightforward
is how I generate menu item lists for either GUI or "console" applications
from an array of structures that describe the routine parameters, function
pointers, etc., which also include a menu item text string somewhere
in the mix, by calling a single function signature "make_menu_list()" for
any
type of identifiable class of routines). Quote:
double add_double_numbers(double *first, size_t n, size_t inc_size) {
unsigned char *p; /* will point to our various "double"s */
double total = 0.0;
size_t i;
>
p = (unsigned char *)first;
for (i = 0; i < n; i++) {
total += *(double *)p;
p += inc_size;
}
return total;
}
>
Let me substitute that in my little test library and see what happens... Quote:
The loop could be compressed to:
>
for (p = (unsigned char *)first, i = 0; i < n; p += inc_size, i++)
total += *(double *)p;
>
for those who prefer to see all the loop invariants in the "for"
expressions.
>
A lot of times, that's me, but in many of the actual cases, I'm doing
SIGNIFICANTLY more processing in the loop, so it ain't going down
to two lines in those cases... Quote:
The reason for taking a "double *" is to force the caller to
pass the address of the first "double" element in the array of
structures, in case the caller wants to do something like:
>
struct S {
int a;
double x;
char *b;
FILE *c;
/* etc */
};
struct S arr[SIZE];
double result;
...
result = add_double_numbers(<args here to total up "arr">);
>
which in this case should be:
>
result = add_double_numbers(&arr[0].x, SIZE, sizeof arr[0]);
>
and *not*:
>
result = add_double_numbers(&arr[0], SIZE, sizeof arr[0]); /*WRONG*/
>
(Note that you could actually make the latter work by passing not
only a "byte spacing from double to double", i.e., inc_size, but
also an "offset from base to first double" element. There is
no real need, in this case: we can just include the offset in
the first argument. Some might like the symmetry of &arr[0] and
sizeof arr[0], though, in which case, add one more argument,
offsetof(arr[0], x), and change the first formal parameter to
"void *base" and make the other obvious required changes.)
OK, let me play around with this stuff a little, thanks...
---
William Ernest Reid | | | | re: What is wrong with this code?
Richard Tobin <richard@cogsci.ed.ac.ukwrote in message
news:f280o9$g5l$2@pc-news.cogsci.ed.ac.uk... Quote:
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote:
> Quote:
typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
To avoid replicating the fields here, you could do
>
typedef struct {
unsigned num_values;
VALUES total[MAX_VALUES];
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
and refer to v.total.value1 instead of v.tot_value_1, etc.
> Quote:
double add_double_numbers
(void *number,unsigned num_numbers,unsigned inc_size) {
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
unsigned number_num=0;
double total=0.0;
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
total+=*double_ptr;
inc_ptr+=inc_size;
number_num++;
}
return total;
}
>
I would prefer something like:
>
double add_double_numbers(double *base, size_t count, size_t stride)
{
unsigned char *byte_ptr = (unsigned char *)base;
unsigned i;
double total=0.0;
>
for(i=0; i<count; i++)
{
total += *(double *)byte_ptr;
byte_ptr += stride;
}
>
return total;
}
>
Since the function only works for doubles, you gain nothing by making
the argument void *; use double * to emphasise its meaning.
>
OK, that's a good point, my problem is that I'm not that clever at
writing "C" code, so let me try this out and see how it works... Quote:
size_t is the right type for object counts and sizes (cf calloc()).
>
Yes, although in most all cases I don't think I'll be exceeding
an unsigned... Quote:
I prefer my variable names; others may disagree. ("Stride" is a
standard term for this sort of distance between successive elements.)
>
Never really heard of it... Quote:
There's no need to use both void and char pointers; converting a
correctly aligned pointer to and from a char pointer is guaranteed to
work. "Char" would be just as correct as "unsigned char" but the
latter is perhaps better for generic byte pointers.
>
Seems like I get some warnings when I get a little too frisky with
pointer assignments and casts, and I don't use code that has warnings...let
me see what happens... Quote:
Using a cast in the accumulating expression instead of an extra
variable and assignment might not be to everyone's taste, but reducing
the vertical size of a function aids readability in my opinion.
>
When a loop is over a sequence of integers, a for loop is clearer than
a while loop.
>
Yeah, more straightforward to maintain and code in the first place,
too...there is no particular logic as to why I used a "while" loop in the
test code I posted...
---
William Ernest Reid | | | | re: What is wrong with this code?
On Sun, 13 May 2007 20:33:11 GMT, "Bill Reid"
<hormelfree@happyhealthy.netwrote: Quote:
>
>Walter Roberson <roberson@ibd.nrc-cnrc.gc.cawrote in message
>news:f27kud$50$1@canopus.cc.umanitoba.ca... Quote:
>In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
>Bill Reid <hormelfree@happyhealthy.netwrote:
>>
>You fail to include <stdio.h>, which would affect the interpretation
>of printf(), possibly causing garbage values to be printed out.
>>
>Uh, yeah, for me on this compiler, just a warning, I think. I haven't
>actually compiled the actual code I posted, just similar stuff...
No, it is a diagnostic. The fact that your compiler calls it a
warning is irrelevant. The error causes undefined behavior. Quote:
> Quote:
>Other than that: what is the difference between the output you
>see and the output you expect?
>
>I get exactly what I expect. Honestly, I was looking for some
>type of criticism of the general approach for accessing structure
>elements in add_double_numbers(), that's all.
If you haven't compiled the code, then how do you get what you expect? Quote:
> Quote:
> There are some ideas so wrong that only a very intelligent person
> could believe in them. -- George Orwell
>
>That is precisely the point, that is precisely the point. Here, let's
>try again...what is wrong with this code?
It suffers from attempting to implement a really poor design. You go
through ridiculous contortions whose only apparent purpose is to avoid
using a pointer to struct.
A little horizontal white space would make your code a lot more
readable. Quote:
>
>#include <stdio.h /* !!!!!!!!!!!! */
>
>#define MAX_VALUES 64
>
>typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
>
>typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
>VALUES_STRUCT values_struct=
>{3,0,0.0,0.0,0.0,{{1,1.0,1.0,1.0},{1,1.0,1.0,1.0} ,{1,1.0,1.0,1.0}}};
The use of a global struct is another unnecessary design flaw. Quote:
>
>double add_double_numbers
>(void *number,unsigned num_numbers,unsigned inc_size) {
If you change the first parameter to VALUES *struct_ptr, you can
eliminate the third parameter .. Quote:
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
and all three of these ... Quote:
unsigned number_num=0;
double total=0.0;
>
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
and both of these ... Quote:
total+=*double_ptr;
and change the second expression to struct_ptr->value_4 Quote:
inc_ptr+=inc_size;
and replace this with a simple
struct_ptr++; The common idiom for this loop would be
for (number_num = 0;
number_num < num_numbers;
number_num++, struct_ptr++){
and delete the last two lines of "manual increments." Quote:
>
return total;
}
>
>void add_value_4(void) {
>
values_struct.tot_value_4=add_double_numbers
(&values_struct.values[0].value_4,values_struct.num_values,
sizeof(VALUES));
The argument list would then be
(values_struct.values, values_struct.num_values) Quote:
>
printf("\nThe total is %f",values_struct.tot_value_4);
Since your value is a double, why not use %lf and avail yourself of
the extra precision. Quote:
}
>
>int main(void) {
>
add_value_4();
>
return 0;
}
>
>---
Remove del for email | | | | re: What is wrong with this code?
In article <od6f43pd20234pdpgmtdfi6r8o3it9fokh@4ax.com>,
Barry Schwarz <schwarzb@doezl.netwrote: Quote:
>It suffers from attempting to implement a really poor design. You go
>through ridiculous contortions whose only apparent purpose is to avoid
>using a pointer to struct.
I think you've missed the point. It's intended to be usable with
different structures and different members of the structures. Of
course, a comment explaining that would be a good idea!
-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963. | | | | re: What is wrong with this code?
>Richard Tobin <richard@cogsci.ed.ac.ukwrote in message Quote:
>news:f280o9$g5l$2@pc-news.cogsci.ed.ac.uk... Quote:
>I prefer my variable names; others may disagree. ("Stride" is a
>standard term for this sort of distance between successive elements.)
In article <1SM1i.145726$VU4.121701@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote: Quote:
>Never really heard of it...
It is a compiler-geek term, found in "array descriptors" in languages
that have such things (the common keywords here are "base",
"bound(s)", "offset", and "stride"). I almost used it, but decided
to stick with the original name, when I switched to "i" and "n".
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers. | | | | re: What is wrong with this code?
Chris Torek wrote: Quote: Quote:
>Richard Tobin wrote:
>> Quote:
>>("Stride" is a standard term for this sort of distance between
>>successive elements.)
>
Bill Reid wrote:
> Quote:
>Never really heard of it...
>
It is a compiler-geek term, found in "array descriptors" in languages
that have such things
It's also pretty common in computer graphics, where it denotes, for
example, the distance in bytes between the start of two successive rows
of an image. Because of alignment, interleaving, bitplaning, and other
things, this distance often differs from the one that might be inferred
from the image width and number of bits per pixel.
- Ernie http://home.comcast.net/~erniew | | | | re: What is wrong with this code?
Ernie Wright said: Quote:
Chris Torek wrote:
> Quote:
>["Stride"] is a compiler-geek term, found in "array descriptors"
>in languages that have such things
>
It's also pretty common in computer graphics, where it denotes,
for example, the distance in bytes between the start of two
successive rows of an image. Because of alignment, interleaving,
bitplaning, and other things, this distance often differs from
the one that might be inferred from the image width and number
of bits per pixel.
To give a slightly different example of "stride", VGA gives you eight
(or possibly sixteen?) pages of 80x25 video memory, each of which
occupies 2000 bytes (80 x 25 x 2), but nevertheless starts on a
2048-byte boundary. I think this was possibly more for convenience than
for speed; 2048-byte boundaries are easy to remember, ending as they do
in either 0x...000 or 0x...800.
To the terminally insane, this meant you had a whole bunch of 48-byte
blocks where you could squirrel away stuff that wouldn't fit anywhere
else... </blush>
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at the above domain, - www. | | | | re: What is wrong with this code?
In article <CPedncwTkPrCZdrbnZ2dnUVZ8sqjnZ2d@bt.com>,
Richard Heathfield <rjh@see.sig.invalidwrote: Quote:
Ernie Wright said:
> Quote:
Chris Torek wrote: Quote:
["Stride"] is a compiler-geek term, found in "array descriptors"
in languages that have such things
It's also pretty common in computer graphics, where it denotes,
for example, the distance in bytes between the start of two
successive rows of an image. Because of alignment, interleaving,
bitplaning, and other things, this distance often differs from
the one that might be inferred from the image width and number
of bits per pixel.
>
To give a slightly different example of "stride", VGA gives you eight
(or possibly sixteen?) pages of 80x25 video memory, each of which
occupies 2000 bytes (80 x 25 x 2), but nevertheless starts on a
2048-byte boundary. I think this was possibly more for convenience than
for speed; 2048-byte boundaries are easy to remember, ending as they do
in either 0x...000 or 0x...800.
>
To the terminally insane, this meant you had a whole bunch of 48-byte
blocks where you could squirrel away stuff that wouldn't fit anywhere
else... </blush>
Why does this remind me of the old Apple II's "screen holes"? :)
--
Don Bruder - dakidd@sonic.net - If your "From:" address isn't on my whitelist,
or the subject of the message doesn't contain the exact text "PopperAndShadow"
somewhere, any message sent to this address will go in the garbage without my
ever knowing it arrived. Sorry... <http://www.sonic.net/~dakiddfor more info | | | | re: What is wrong with this code?
Chris Torek <nospam@torek.netwrote in message
news:f27up702nh2@news5.newsguy.com... Quote:
In article <bCK1i.144938$VU4.58740@bgtnsc05-news.ops.worldnet.att.net>
Bill Reid <hormelfree@happyhealthy.netwrote:
Quote: Quote:
I get exactly what I expect. Honestly, I was looking for some
type of criticism of the general approach for accessing structure
elements in add_double_numbers(), that's all.
>
Oh ... in that case, as far as I can tell, the code is valid. It
does seem "slightly dangerous" (in the sense that it would be easy
for a caller to provide improper arguments, and then have everything
go kaboom). Also, while we tend to discourage casts in comp.lang.c,
I would probably go ahead and use them here, and make a few other
minor changes:
>
/*
* Iterate over some kind of array, which may be an array of structures
* or array of arrays, in which there is at least one "double" element.
* Add up the n "double" elements that are spaced apart by
* "inc_size" bytes, given a pointer to the first such "double".
*/
double add_double_numbers(double *first, size_t n, size_t inc_size) {
unsigned char *p; /* will point to our various "double"s */
double total = 0.0;
size_t i;
>
p = (unsigned char *)first;
for (i = 0; i < n; i++) {
total += *(double *)p;
p += inc_size;
}
return total;
}
>
OK, I've tested this and it is a perfect "drop-in" fit for any of my
fundamental libraries that implement this type of structure element
access. It's got to be a little quicker because it eliminates the unneeded
pointer assignments (considering these libraries perform at least several
hundred billion loops a day, that's got to be worth a few seconds), and
should be more "type-safe" as well for ongoing development.
So thanks again because that's EXACTLY what I was looking for;
my original design was just the result of my general inability to handle
pointers very adroitly...
---
William Ernest Reid | | | | re: What is wrong with this code?
Richard Tobin <richard@cogsci.ed.ac.ukwrote in message
news:f280o9$g5l$2@pc-news.cogsci.ed.ac.uk... Quote:
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote:
>
To avoid replicating the fields here, you could do
>
typedef struct {
unsigned num_values;
VALUES total[MAX_VALUES];
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
and refer to v.total.value1 instead of v.tot_value_1, etc.
>
Yeah, for the purposes of this "toy" code, but of course I really
WASN'T trying to add 1.0+1.0+1.0, despite what some people
seem to think! An actual structure I use might consist of several
dozen "results" or "descriptive" variables along with pointers to
several malloc'd arrays of 50-100 thousand structures containing
related values of floats, doubles, long doubles, ints... Quote:
>
I would prefer something like:
>
double add_double_numbers(double *base, size_t count, size_t stride)
{
unsigned char *byte_ptr = (unsigned char *)base;
unsigned i;
double total=0.0;
>
for(i=0; i<count; i++)
{
total += *(double *)byte_ptr;
byte_ptr += stride;
}
>
return total;
}
>
Since the function only works for doubles, you gain nothing by making
the argument void *; use double * to emphasise its meaning.
>
Yup, this is almost identical to what Chris Torek came up with,
works like a champ. Thanks. Quote:
size_t is the right type for object counts and sizes (cf calloc()).
>
Yes, "technically", which of course what this is all about... Quote:
I prefer my variable names; others may disagree.
I tend to prefer nice big preferably unabbreviated English words that
I can understand immediately, but that's not really a "C" convention, now
is it? Quote:
>
There's no need to use both void and char pointers; converting a
correctly aligned pointer to and from a char pointer is guaranteed to
work.
Yeah, this was a confusion on my part...I didn't really know that,
at least in a useful sense...
---
William Ernest Reid | | | | re: What is wrong with this code?
Barry Schwarz <schwarzb@doezl.netwrote in message
news:od6f43pd20234pdpgmtdfi6r8o3it9fokh@4ax.com... Quote:
On Sun, 13 May 2007 20:33:11 GMT, "Bill Reid"
<hormelfree@happyhealthy.netwrote: Quote:
Walter Roberson <roberson@ibd.nrc-cnrc.gc.cawrote in message
news:f27kud$50$1@canopus.cc.umanitoba.ca... <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>, Quote: Quote: Quote:
Bill Reid <hormelfree@happyhealthy.netwrote:
>
You fail to include <stdio.h>, which would affect the interpretation
of printf(), possibly causing garbage values to be printed out.
>
Uh, yeah, for me on this compiler, just a warning, I think. I haven't
actually compiled the actual code I posted, just similar stuff...
>
No, it is a diagnostic. The fact that your compiler calls it a
warning is irrelevant. The error causes undefined behavior.
> Quote: Quote:
Other than that: what is the difference between the output you
see and the output you expect?
I get exactly what I expect. Honestly, I was looking for some
type of criticism of the general approach for accessing structure
elements in add_double_numbers(), that's all.
>
If you haven't compiled the code, then how do you get what you expect?
>
Ummmm, let's think about this...maybe because I actually compiled
and linked two separate "translation units" with "extern" declarations
and typedefs in a what's called a "header file"? Maybe I just cut and
pasted that code into what appears to be a single source code file,
and just forgot to paste in the include stdio.h define? Naaahhhh,
never happen... Quote: Quote: Quote:
There are some ideas so wrong that only a very intelligent person
could believe in them. -- George Orwell
That is precisely the point, that is precisely the point. Here, let's
try again...what is wrong with this code?
>
It suffers from attempting to implement a really poor design. You go
through ridiculous contortions whose only apparent purpose is to avoid
using a pointer to struct.
>
To repeat myself:
"That is precisely the point, that is precisely the point."
Hey, why not take it a step further; I'm actually going through the
ridiculous contortions to avoid using a pointer to an ARRAY. After
all, why couldn't I just declare four separate arrays, with four
separate variables for the number of elements in the arrays?
What the hell is the matter with me, anyway? Quote:
A little horizontal white space would make your code a lot more
readable.
Another egregious personality flaw, perhaps requiring "professional"
help... Quote: Quote:
VALUES_STRUCT values_struct=
{3,0,0.0,0.0,0.0,{{1,1.0,1.0,1.0},{1,1.0,1.0,1.0}, {1,1.0,1.0,1.0}}};
>
The use of a global struct is another unnecessary design flaw.
>
Well, you didn't actually make me laugh here, but you did make
me smile... Quote: Quote:
double add_double_numbers
(void *number,unsigned num_numbers,unsigned inc_size) {
>
If you change the first parameter to VALUES *struct_ptr, you can
eliminate the third parameter ..
>
Actually, thinking about it even more, I know realize that I could
have just done it like this:
double number_4_1=1.0;
double number_4_2=1.0;
double number_4_3=1.0;
double add_double_numbers_4(void) {
return (number_4_1+number_4_2+number_4_3);
}
OK, call off the hunt, we have a winner!!! Quote: Quote:
void *void_ptr=NULL;
char *inc_ptr=number;
double *double_ptr=NULL;
>
and all three of these ...
>
Yeah, I've got you beat, but you helped! Quote: Quote:
unsigned number_num=0;
double total=0.0;
while(number_num<num_numbers) {
void_ptr=inc_ptr;
double_ptr=void_ptr;
>
and both of these ...
>
Mine's much better, but again, you helped! Quote: Quote:
total+=*double_ptr;
>
and change the second expression to struct_ptr->value_4
> Quote:
inc_ptr+=inc_size;
>
and replace this with a simple
struct_ptr++;
> >
Well, now I FINALLY know how to increment through an array of
structs... Quote: Quote:
printf("\nThe total is %f",values_struct.tot_value_4);
>
Since your value is a double, why not use %lf and avail yourself of
the extra precision.
>
Oh, I guess I just thought it was overkill for adding 1.0+1.0+1.0...but
you never know, tomorrow, I might try to add 2.0+2.0+2.0!!!
---
William Ernest Reid | | | | re: What is wrong with this code?
"Bill Reid" <hormelfree@happyhealthy.netwrites: Quote:
Barry Schwarz <schwarzb@doezl.netwrote in message
news:od6f43pd20234pdpgmtdfi6r8o3it9fokh@4ax.com...
[...] Quote: Quote:
>If you haven't compiled the code, then how do you get what you expect?
>>
Ummmm, let's think about this...maybe because I actually compiled
and linked two separate "translation units" with "extern" declarations
and typedefs in a what's called a "header file"? Maybe I just cut and
pasted that code into what appears to be a single source code file,
and just forgot to paste in the include stdio.h define? Naaahhhh,
never happen...
And you expected us to know that, even if you didn't happen to tell
us?
[...] Quote: Quote:
>A little horizontal white space would make your code a lot more
>readable.
>
Another egregious personality flaw, perhaps requiring "professional"
help...
Why do you respond to good advice with sarcasm?
[...] Quote: Quote:
>The use of a global struct is another unnecessary design flaw.
>>
Well, you didn't actually make me laugh here, but you did make
me smile...
Global variables are usually a bad idea. I fail to see the humor.
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister" | | | | re: What is wrong with this code?
Keith Thompson said: Quote:
"Bill Reid" <hormelfree@happyhealthy.netwrites: Quote:
>Barry Schwarz <schwarzb@doezl.netwrote in message
>news:od6f43pd20234pdpgmtdfi6r8o3it9fokh@4ax.com.. .
[...] Quote: Quote:
>>A little horizontal white space would make your code a lot more
>>readable.
>>
>Another egregious personality flaw, perhaps requiring "professional"
>help...
>
Why do you respond to good advice with sarcasm?
Presumably because he isn't interested in good advice. Which suits me
just fine. Into the bozo bin with him...
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at the above domain, - www. | | | | re: What is wrong with this code?
In article <s2U1i.147614$VU4.94072@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote: Quote:
>I tend to prefer nice big preferably unabbreviated English words that
>I can understand immediately, but that's not really a "C" convention, now
>is it?
I like unabbreviated names because they're easy to understand, but
I like short names because then expressions and statements fit on
a single line, making it easier to grasp the structure. Overall
I find the latter approach results in more readable code.
I suspect a background in mathematics also inclines one to short
variable names; mathematicians almost invariably use single-letter
names.
-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963. | | | | re: What is wrong with this code?
On May 14, 11:37 am, Barry Schwarz <schwa...@doezl.netwrote: Quote:
On Sun, 13 May 2007 20:33:11 GMT, "Bill Reid" Quote:
printf("\nThe total is %f",values_struct.tot_value_4);
>
Since your value is a double, why not use %lf and avail yourself of
the extra precision.
Huh? "%f" is the specifier for printing doubles. %lf causes
undefined behaviour in C90. (In C99 it has the same effect
as %f). | | | | re: What is wrong with this code?
On May 14, 10:54 pm, rich...@cogsci.ed.ac.uk (Richard Tobin) wrote: Quote:
I suspect a background in mathematics also inclines one to short
variable names; mathematicians almost invariably use single-letter
names.
A minor notational quirk. In mathematics, "bar" means b multiplied
by a multiplied by r ! In fact, the first algebra text used words for
variable names -- specifically, the Arabic word for "the thing".
In mathematics you rarely, if ever, come across a situation where
you would need to have multiple variables with descriptive names.
Most multi-variable situations call for the variables to be held
in arrays of some form or another. | | | | re: What is wrong with this code?
Old Wolf wrote: Quote:
On May 14, 11:37 am, Barry Schwarz <schwa...@doezl.netwrote: Quote:
>On Sun, 13 May 2007 20:33:11 GMT, "Bill Reid" Quote:
>> printf("\nThe total is %f",values_struct.tot_value_4);
>Since your value is a double, why not use %lf and avail yourself of
>the extra precision.
>
Huh? "%f" is the specifier for printing doubles. %lf causes
undefined behaviour in C90. (In C99 it has the same effect
as %f).
>
Hu?? back at you.
check the help below.
l for long int or double,
f for float.
On all the systems I know, where float is 32bit
and double 64, f is for float, and lf for double.
The format for the printf family of functions is as follows:
% flags width .precision type prefix format type
.--------------------------.--------------------------------------.
| Flags | Format Type |
| - (left justify) | d,i (signed decimal) |
| + (prefix with sign) | u (unsigned decimal integer) |
| blank (prefix with blank)| o (unsigned octal integer) |
| # (modifies o,x,X, | x,X (unsigned hex integer) |
| e,E,f,g,G) | f (fixed-point float) |
.--------------------------. e,E (scientific notation) .
| Type Prefix | g,G (%e or %f; whichever is shorter) |
| F (far pointer) | c (single character) |
| N (near pointer) | s (string) |
| h (short int) | p (pointer) |
| l,L (long int or double) | n (character count) |
.--------------------------.--------------------------------------. | | | | re: What is wrong with this code?
In article <4648f602$0$16942$ba620dc5@text.nova.planet.nl>,
Sjouke Burry <burrynulnulfour@ppllaanneett.nnlllwrote: Quote: Quote: Quote:
>>Since your value is a double, why not use %lf and avail yourself of
>>the extra precision.
Quote: Quote:
>Huh? "%f" is the specifier for printing doubles. %lf causes
>undefined behaviour in C90. (In C99 it has the same effect
>as %f).
Quote:
>Hu?? back at you.
>check the help below.
Get better help.
The C99 standard says that the l modifier "has no effect on a following
a, A, e, E, f, F, g, or G conversion specifier".
The reason for this is that printf() is a variadic function, so the
arguments are subject to the "default argument promotions". In
particular, arguments of type float are converted to double before the
function is called. So there is no way to pass a float to printf(),
so %f always gets a double.
Of course, things could have been defined so that printf() converts
its argument from a double to a float if the format is %f, but that
would be pointless.
-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963. | | | | re: What is wrong with this code?
Sjouke Burry <burrynulnulfour@ppllaanneett.nnlllwrites: Quote:
Old Wolf wrote: Quote:
>On May 14, 11:37 am, Barry Schwarz <schwa...@doezl.netwrote: Quote:
>>On Sun, 13 May 2007 20:33:11 GMT, "Bill Reid"
>>> printf("\nThe total is %f",values_struct.tot_value_4);
>>Since your value is a double, why not use %lf and avail yourself of
>>the extra precision.
>Huh? "%f" is the specifier for printing doubles. %lf causes
>undefined behaviour in C90. (In C99 it has the same effect
>as %f).
>>
Hu?? back at you.
check the help below.
>
l for long int or double,
f for float.
>
On all the systems I know, where float is 32bit
and double 64, f is for float, and lf for double.
>
>
The format for the printf family of functions is as follows:
>
% flags width .precision type prefix format type
>
.--------------------------.--------------------------------------.
| Flags | Format Type |
| - (left justify) | d,i (signed decimal) |
| + (prefix with sign) | u (unsigned decimal integer) |
| blank (prefix with blank)| o (unsigned octal integer) |
| # (modifies o,x,X, | x,X (unsigned hex integer) |
| e,E,f,g,G) | f (fixed-point float) |
.--------------------------. e,E (scientific notation) .
| Type Prefix | g,G (%e or %f; whichever is shorter) |
| F (far pointer) | c (single character) |
| N (near pointer) | s (string) |
| h (short int) | p (pointer) |
| l,L (long int or double) | n (character count) |
.--------------------------.--------------------------------------.
That table is either wrong or just ambiguously written.
"F" and "N" are non-standard, as are "far" and "near" pointers, so
I'll ignore those.
The "%f" format expects an argument of type double. It can also be
used with an argument of type float, but that's only because float
arguments are promoted to double when they match the "..." of a
variadic function.
The format for type "long double" is "%Lf". I suspect that
the entry in the table:
l,L (long int or double)
really means "l for long int, L for long double"; whoever wrote it
should be embarrassed.
In C90, "%lf" invokes undefined behavior. In C99, "%lf" means the
same thing as "%f".
So, in C99, or in an implementation that provides the C99 feature of
allowing "%lf", you *can* use "%f" for float and "%lf" for double.
(You can also, if you like, use "%lf" for float and "%f" for double,
but I wouldn't recommend it.) If you care about your code being
portable, you should use "%f" for both float and double, since that's
required to work for either C90 or C99.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister" | | | | re: What is wrong with this code?
Richard Heathfield wrote: .... snip ... Quote:
>
To give a slightly different example of "stride", VGA gives you
eight (or possibly sixteen?) pages of 80x25 video memory, each of
which occupies 2000 bytes (80 x 25 x 2), but nevertheless starts
on a 2048-byte boundary. I think this was possibly more for
convenience than for speed; 2048-byte boundaries are easy to
remember, ending as they do in either 0x...000 or 0x...800.
>
To the terminally insane, this meant you had a whole bunch of
48-byte blocks where you could squirrel away stuff that wouldn't
fit anywhere else... </blush>
You are really talking about 4k blocks, when you are including an
attribute byte, as in VGA.
--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>
<http://www.aaxnet.com/editor/edit043.html>
<http://kadaitcha.cx/vista/dogsbreakfast/index.html>
cbfalconer at maineline dot net
--
Posted via a free Usenet account from http://www.teranews.com | | | | re: What is wrong with this code?
CBFalconer said: Quote:
Richard Heathfield wrote: ... snip ... Quote:
>>
>To give a slightly different example of "stride", VGA gives you
>eight (or possibly sixteen?) pages of 80x25 video memory, each of
>which occupies 2000 bytes (80 x 25 x 2), but nevertheless starts
>on a 2048-byte boundary. I think this was possibly more for
>convenience than for speed; 2048-byte boundaries are easy to
>remember, ending as they do in either 0x...000 or 0x...800.
>>
>To the terminally insane, this meant you had a whole bunch of
>48-byte blocks where you could squirrel away stuff that wouldn't
>fit anywhere else... </blush>
>
You are really talking about 4k blocks, when you are including an
attribute byte, as in VGA.
Sorry, you're right - 80x25x2 (see above) is actually 4000, not 2000. So
much for arithmetic. Yes, 48 spare bytes looked wrong when I wrote it,
but I trusted my arithmetic rather than my memory!
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at the above domain, - www. | | | | re: What is wrong with this code?
On 13 May 2007 21:42:33 GMT, richard@cogsci.ed.ac.uk (Richard Tobin)
wrote: Quote:
In article <3eI1i.144346$VU4.102084@bgtnsc05-news.ops.worldnet.att.net>,
Bill Reid <hormelfree@happyhealthy.netwrote:
> Quote:
typedef struct {
unsigned value_1;
double value_2;
double value_3;
double value_4;
} VALUES;
typedef struct {
unsigned num_values;
unsigned tot_value_1;
double tot_value_2;
double tot_value_3;
double tot_value_4;
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
To avoid replicating the fields here, you could do
>
typedef struct {
unsigned num_values;
VALUES total[MAX_VALUES];
Ahem. No array for this one. Quote:
VALUES values[MAX_VALUES];
} VALUES_STRUCT;
>
and refer to v.total.value1 instead of v.tot_value_1, etc.
>
Right.
<snip rest>
- formerly david.thompson1 || achar(64) || worldnet.att.net |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,223 network members.
|