Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > code snippet

Reply
Thread Tools

code snippet

 
 
Ben Bacarisse
Guest
Posts: n/a
 
      12-19-2011
"Bill Cunningham" <(E-Mail Removed)> writes:

> I have this code snippet that won't compile with gcc -c and I get errors
> of needing casts. This is untested code of course and I thought I'd ask for
> opinions on what I've done wrong.


I'll make a few general remarks...

> #include <stdio.h>
>
> void *get(void *pv)
> {
> double price;
> long int date;
> unsigned int number;
> int check;
> FILE *fp;
> if ((fp = fopen("num", "r")) == NULL) {
> perror("fopen error");
> return 1;
> }
> if ((check = fscanf(fp, "%u %f %l", &number, &price, &date)) == EOF) {


(you need %lf to read a double. %f is for float)

> printf("%d\n", ferror(fp));
> clearerr(fp);
> return 1;
> }


This is an example of what I'd call programming upside down. Look at
all the detail there: the file name, the format, the error messages, the
clearing of the IO error and so on, but *no code to do any real work*.
You've started walking, but you have no idea where you are going. A
clue to that is the function prototype. The name is entirely
noncommittal, and while there are valid uses of void *, here I think
they mean "I don't know what I need to pass to this function and I have
no idea what it should return".

When I program, I usually start with an outline of the overall behaviour
i.e. I start with main. This is broken down into functions that can do
the constituent parts of the job. Even these functions are often
written in outline first with the focus on what they actually do. The
parts you've worked out in detail, I will leave for later. For one
thing, I want to start testing as soon as possible, so I need a function
that works right away. If I find, either in testing or when finishing
these sketched functions, that things are going wrong, I can change the
design before I've sunk too much effort into it.

So my functions usually start out having a very specific name and
prototype:

double get_stock_price_on_date(FILE *fp, long int date)

but the body will often be what's called a stub:

double get_price_on_date(FILE *fp, long int date)
{
// Rewind file.
// Loop until third field equals date
// If date not found I'll return a negative price.
return 42;
}

Once it's all written like this I can start testing and filling in
the details as I go. If you can't do this, it is often because you
don't know, in enough detail, what your program is to do. It's almost
impossible to program with out a clear objective, so when I find myself
unable to sketch things out like this, it means I need to think more
about my objectives.

A detail: always test for fscanf success. As you say elsewhere the
returns are complex but if it returns 3 you got the three things you
need and you can do what you need to with them. You can (at least
initially) treat any return that is not 3 as an error. You can waste
ages dealing with all the various ways in which things have gone wrong,
so start instead with writing what happens when the input worked.

--
Ben.
 
Reply With Quote
 
 
 
 
Rui Maciel
Guest
Posts: n/a
 
      12-19-2011
Bill Cunningham wrote:

> Geoff wrote:
>
>> Apart from the missing closing brace?

>
> Oh...Yeah.
>
>> The compiler is expecting your function to return a pointer. You are
>> not doing that. Furthermore, not all paths through the function as
>> shown return a value.

>
> It looks to me that they all return a 1 on error and I guess I need to
> fix that. I would need to set a pointer to a value of 1. Let's see...
>
> int *error=1;
>
> And in the functions changed to return error;
> Sound good.
>
> I forget with this new bash I have been working with how to redirect to
> stderr. Maybe this will undo the errors.
>
> Bill


Do you have the freedom to redefine the get() function? If so, I would
suggest that you defined it so that it returned a meaningful result instead
of a pointer. For example, you could define an enum which encompasses all
possible error codes and then rely on that enum definition to return error
codes which are actually meaningful. By doing so, your code would become a
bit easier to read and understand (i.e., no more magic numbers), not to
mention a bit more structured.

For example:

<code>
enum ErrorCodes
{
ERR_OK = 0,
ERR_FOPEN_ERROR,
//...
ERR_UNKNOWN // only returned in SNAFU cases
}

enum ErrorCodes get(void *pv)
{
double price;
long int date;
unsigned int number;
int check;
FILE *fp;
if ((fp = fopen("num", "r")) == NULL) {
perror("fopen error");
return ERR_FOPEN_ERROR;
}
if ((check = fscanf(fp, "%u %f %l", &number, &price, &date)) == EOF) {
printf("%d\n", ferror(fp));
clearerr(fp);
return ERR_FOPEN_ERROR;
}

//...

return ERR_UNKNOWN; // in case of something going horribly wrong
}


int main(void)
{
// snip

enum ErrorCodes error;
error = get(foo);

if(error != ERR_OK)
{
switch(error) // this could also be a predefined function
{
// handle any potential error in here
}
}

// snip
return 0;
}

</code>


Hope this helps,
Rui Maciel
 
Reply With Quote
 
 
 
 
Bill Cunningham
Guest
Posts: n/a
 
      12-19-2011
Rui Maciel wrote:

> Do you have the freedom to redefine the get() function? If so, I
> would suggest that you defined it so that it returned a meaningful
> result instead of a pointer. For example, you could define an enum
> which encompasses all possible error codes and then rely on that enum
> definition to return error codes which are actually meaningful. By
> doing so, your code would become a bit easier to read and understand
> (i.e., no more magic numbers), not to mention a bit more structured.
>
> For example:
>
> <code>
> enum ErrorCodes
> {
> ERR_OK = 0,
> ERR_FOPEN_ERROR,
> //...
> ERR_UNKNOWN // only returned in SNAFU cases
> }
>
> enum ErrorCodes get(void *pv)
> {
> double price;
> long int date;
> unsigned int number;
> int check;
> FILE *fp;
> if ((fp = fopen("num", "r")) == NULL) {
> perror("fopen error");
> return ERR_FOPEN_ERROR;
> }
> if ((check = fscanf(fp, "%u %f %l", &number, &price, &date)) ==
> EOF) { printf("%d\n", ferror(fp));
> clearerr(fp);
> return ERR_FOPEN_ERROR;
> }
>
> //...
>
> return ERR_UNKNOWN; // in case of something going horribly wrong
> }
>
>
> int main(void)
> {
> // snip
>
> enum ErrorCodes error;
> error = get(foo);
>
> if(error != ERR_OK)
> {
> switch(error) // this could also be a predefined function
> {
> // handle any potential error in here
> }
> }
>
> // snip
> return 0;
> }
>
> </code>


I can change the parameters I guess but I want this function to return
at times an unsigned int, sometimes a double, sometimes a signed int.
The only way I know to return multiple types without getting into the
possibility of structs is a generic pointer to point to where the values are
stored.

Bill


 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      12-19-2011
Ben Bacarisse wrote:
> "Bill Cunningham" <(E-Mail Removed)> writes:
>
>> I have this code snippet that won't compile with gcc -c and I
>> get errors of needing casts. This is untested code of course and I
>> thought I'd ask for opinions on what I've done wrong.

>
> I'll make a few general remarks...
>
>> #include <stdio.h>
>>
>> void *get(void *pv)
>> {
>> double price;
>> long int date;
>> unsigned int number;
>> int check;
>> FILE *fp;
>> if ((fp = fopen("num", "r")) == NULL) {
>> perror("fopen error");
>> return 1;
>> }
>> if ((check = fscanf(fp, "%u %f %l", &number, &price, &date)) ==
>> EOF) {

>
> (you need %lf to read a double. %f is for float)
>
>> printf("%d\n", ferror(fp));
>> clearerr(fp);
>> return 1;
>> }

>
> This is an example of what I'd call programming upside down. Look at
> all the detail there: the file name, the format, the error messages,
> the clearing of the IO error and so on, but *no code to do any real
> work*. You've started walking, but you have no idea where you are
> going. A clue to that is the function prototype. The name is
> entirely noncommittal, and while there are valid uses of void *, here
> I think they mean "I don't know what I need to pass to this function
> and I have no idea what it should return".
>
> When I program, I usually start with an outline of the overall
> behaviour i.e. I start with main. This is broken down into functions
> that can do the constituent parts of the job. Even these functions
> are often written in outline first with the focus on what they
> actually do. The parts you've worked out in detail, I will leave for
> later. For one thing, I want to start testing as soon as possible,
> so I need a function that works right away. If I find, either in
> testing or when finishing these sketched functions, that things are
> going wrong, I can change the design before I've sunk too much effort
> into it.
>
> So my functions usually start out having a very specific name and
> prototype:
>
> double get_stock_price_on_date(FILE *fp, long int date)
>
> but the body will often be what's called a stub:
>
> double get_price_on_date(FILE *fp, long int date)
> {
> // Rewind file.
> // Loop until third field equals date
> // If date not found I'll return a negative price.
> return 42;
> }


The thing is your function always returns a double. I want my get to
return multiple types. The only 2 things I know to do is use a pointer of a
type that points to the location of stock price, or line number, or date.
The only other thing I know to do is pack the various types into one type. A
struct. Does this make sense?

> Once it's all written like this I can start testing and filling in
> the details as I go. If you can't do this, it is often because you
> don't know, in enough detail, what your program is to do. It's almost
> impossible to program with out a clear objective, so when I find
> myself unable to sketch things out like this, it means I need to
> think more about my objectives.
>
> A detail: always test for fscanf success. As you say elsewhere the
> returns are complex but if it returns 3 you got the three things you
> need and you can do what you need to with them. You can (at least
> initially) treat any return that is not 3 as an error. You can waste
> ages dealing with all the various ways in which things have gone
> wrong, so start instead with writing what happens when the input
> worked.



 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      12-19-2011
Geoff wrote:
> On Mon, 19 Dec 2011 00:01:35 -0500, "Bill Cunningham"
> <(E-Mail Removed)> wrote:
>
>> Other functions are going to do things with the data gathered
>> from the function get. What get returns is supposed to be passed to
>> other functions.

>
> That's great, except that you have declared number, price and date as
> local variables within the function and they will go out of scope the
> moment 'get' returns.


Good point.

Bill


 
Reply With Quote
 
Morris Keesan
Guest
Posts: n/a
 
      12-19-2011
On Mon, 19 Dec 2011 16:38:54 -0500, Bill Cunningham <(E-Mail Removed)>
wrote:
....
>>> void *get(void *pv)
>>> {


....

> I want my get to
> return multiple types. The only 2 things I know to do is use a pointer
> of a type that points to the location of stock price, or line number,
> or date. The only other thing I know to do is pack the various types
> into one type. A struct. Does this make sense?


Look at this style, where you're returning a (void *) which points to
either an unsigned int, a long int, or a double. When another function
calls this get() function, how will it know what type is being returned?

If I were writing a function like this which could return multiple types,
I would have it return an enum which indicates which of the various types
is being returned. This enum could either be an element of a struct
whose other element is a union which could contain any one of the other
types, or I might pass in pointers to each of those types, and return
an enum type telling which of the pointers was used. I would also
define one or more error values for the enum object, which would
indicate that none of the data objects was populated.
--
Morris Keesan -- http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      12-19-2011
Ben Bacarisse wrote:

> I'll make a few general remarks...
>


[code]

> This is an example of what I'd call programming upside down. Look at
> all the detail there: the file name, the format, the error messages,
> the clearing of the IO error and so on, but *no code to do any real
> work*. You've started walking, but you have no idea where you are
> going. A clue to that is the function prototype. The name is
> entirely noncommittal, and while there are valid uses of void *, here
> I think they mean "I don't know what I need to pass to this function
> and I have no idea what it should return".
>
> When I program, I usually start with an outline of the overall
> behaviour i.e. I start with main. This is broken down into functions
> that can do the constituent parts of the job. Even these functions
> are often written in outline first with the focus on what they
> actually do. The parts you've worked out in detail, I will leave for
> later. For one thing, I want to start testing as soon as possible,
> so I need a function that works right away. If I find, either in
> testing or when finishing these sketched functions, that things are
> going wrong, I can change the design before I've sunk too much effort
> into it.
>
> So my functions usually start out having a very specific name and
> prototype:
>
> double get_stock_price_on_date(FILE *fp, long int date)
>
> but the body will often be what's called a stub:


What is a stub? Never heard of it.

[snip]



 
Reply With Quote
 
John Gordon
Guest
Posts: n/a
 
      12-19-2011
In <4eefb902$0$11612$(E-Mail Removed)> "Bill Cunningham" <(E-Mail Removed)> writes:

> What is a stub? Never heard of it.


A stub is an empty function. Its purpose is to serve as a placeholder
for the "real" function which you haven't written yet. It allows you to
design the high-level flow of your program, and have it compile, without
getting bogged down in low-level details.

--
John Gordon A is for Amy, who fell down the stairs
(E-Mail Removed) B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

 
Reply With Quote
 
Rui Maciel
Guest
Posts: n/a
 
      12-20-2011
Bill Cunningham wrote:

> I can change the parameters I guess but I want this function to return
> at times an unsigned int, sometimes a double, sometimes a signed int.
> The only way I know to return multiple types without getting into the
> possibility of structs is a generic pointer to point to where the values
> are stored.


Are you, by any chance, developing a parser? If you are, there are better
ways of handling values extracted from tokens.

But regarding the pointer thing, there are other ways to get that job done.
You can define a union which encompasses every data type which you wish your
function to return, and then rewrite your function so that it returns that
instead of a pointer. In fact, relying on a pointer to do that ends up
being a dirty, convoluted way to do what unions do. Incidentally, the code
generated by GNU Bison happens to rely on unions to handle values extracted
from tokens, and it appears to work well.


Rui Maciel


 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      12-20-2011
Rui Maciel wrote:

> Are you, by any chance, developing a parser?


I don't know. I was going to manually type data into a a text file and
read using fscanf. Maybe a parser is what I want.

If you are, there are
> better ways of handling values extracted from tokens.
>
> But regarding the pointer thing, there are other ways to get that job
> done. You can define a union which encompasses every data type which
> you wish your function to return, and then rewrite your function so
> that it returns that instead of a pointer. In fact, relying on a
> pointer to do that ends up being a dirty, convoluted way to do what
> unions do. Incidentally, the code generated by GNU Bison happens to
> rely on unions to handle values extracted from tokens, and it appears
> to work well.
>
>
> Rui Maciel



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Code snippets, tool to convert basic to .snippet xml? Edwin Knoppert ASP .Net 0 11-30-2005 03:45 PM
Is there a code snippet showing how to do a Redirect on a TreeView event Tom ASP .Net 3 12-01-2004 03:04 AM
j2se 1.5 broke this code snippet - anyone ??? Gil Blais Java 12 07-15-2004 07:37 PM
Request Handler code snippet wanted plz Gil Blais Java 0 04-15-2004 08:23 AM
How can I save my code snippet on toolbox in vs.net? Clare Hsiao ASP .Net 0 02-12-2004 02:01 AM



Advertisments