ANNOUNCE ggets revised

C

CBFalconer

CBFalconer said:
I have modified my ggets utility, to simplify the code and reduce
the requirements on the standard library. The external action is
totally unchanged, so there is no real need for anyone to upgrade.
Available at:

<http://cbfalconer.home.att.net/download/>

I hate to admit it, but I released something with a memory leak.
Fixed. The zip file dated 2006-06-15 has the fix, and is now the
only one found on the above link.
 
F

Frank Silvermann

CBFalconer said:
I hate to admit it, but I released something with a memory leak.
Fixed. The zip file dated 2006-06-15 has the fix, and is now the
only one found on the above link.
Did the memory leak exist five minutes ago? I think I got the revised
one but my question goes to the header:
#ifndef ggets_h_
# define ggets_h_

# ifdef __cplusplus
extern "C" {
# endif

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

# ifdef __cplusplus
}
# endif
#endif
/* END ggets.h */
What is happening with the ifdefs here? They would seem to be building
a statement:
extern "C" { int ... #define ...}
? frank
 
M

Michael Mair

Frank said:
CBFalconer wrote:
my question goes to the header:
#ifndef ggets_h_
# define ggets_h_

# ifdef __cplusplus
extern "C" {
# endif

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

# ifdef __cplusplus
}
# endif
#endif
/* END ggets.h */
What is happening with the ifdefs here? They would seem to be building
a statement:
extern "C" { int ... #define ...}

Yep.
You can assume that every sufficiently new C implementation does
not #define __cplusplus [*] whereas a C++ implementation usually
does.

So the C version of the code just gives you a header with
include guards in which a prototype of fggets() and a macro
definition for ggets() are provided.
The C++ version does essentially the same but marks fggets()
as function stemming from C code (this information is
necessary for linking).

[*] C99 explicitly forbids the implementation to predefine
__cplusplus in any standard library header (6.10.8#5); even
compilers not complying to this standard usually do not
#define __cplusplus.


Cheers
Michael
 
F

Frank Silvermann

Michael said:
Frank said:
CBFalconer wrote:
my question goes to the header:
#ifndef ggets_h_
# define ggets_h_

# ifdef __cplusplus
extern "C" {
# endif

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

# ifdef __cplusplus
}
# endif
#endif
/* END ggets.h */
What is happening with the ifdefs here? They would seem to be
building a statement:
extern "C" { int ... #define ...}

Yep.
You can assume that every sufficiently new C implementation does
not #define __cplusplus [*] whereas a C++ implementation usually
does.

So the C version of the code just gives you a header with
include guards in which a prototype of fggets() and a macro
definition for ggets() are provided.
The C++ version does essentially the same but marks fggets()
as function stemming from C code (this information is
necessary for linking).

[*] C99 explicitly forbids the implementation to predefine
__cplusplus in any standard library header (6.10.8#5); even
compilers not complying to this standard usually do not
#define __cplusplus.
I'm looking for an explicit answer to something I'm assuming,
given that posting non standard stuff in clc would be a first for the
OP. Is everything in that header ISO C, 2006-06-15 ? gruss, frank
 
M

Michael Mair

Frank said:
Michael said:
Frank said:
CBFalconer wrote:

my question goes to the header:
#ifndef ggets_h_
# define ggets_h_

# ifdef __cplusplus
extern "C" {
# endif

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

# ifdef __cplusplus
}
# endif
#endif
/* END ggets.h */
What is happening with the ifdefs here? They would seem to be
building a statement:
extern "C" { int ... #define ...}

Yep.
You can assume that every sufficiently new C implementation does
not #define __cplusplus [*] whereas a C++ implementation usually
does.

So the C version of the code just gives you a header with
include guards in which a prototype of fggets() and a macro
definition for ggets() are provided.
The C++ version does essentially the same but marks fggets()
as function stemming from C code (this information is
necessary for linking).

[*] C99 explicitly forbids the implementation to predefine
__cplusplus in any standard library header (6.10.8#5); even
compilers not complying to this standard usually do not
#define __cplusplus.

I'm looking for an explicit answer to something I'm assuming,
given that posting non standard stuff in clc would be a first for the
OP. Is everything in that header ISO C, 2006-06-15 ? gruss, frank

It definitely is valid as C90 or C99 + TC1 + TC2 code and
everything in between, with the stipulation for pre-C99
implementations that they must not define __cplusplus as
macro identifier.
If you have a pre-C99 implementation that does define
__cplusplus, then you will get a diagnostic ("compiler
error") from it.
Of course, if you yourself invade the implementation
"namespace" and #define __cplusplus, you face the same
problem.

As an aside: The only thing open to debate from a C point
of view is the question whether the header should contain
#include <stdio.h>
or not since it "uses" FILE and stdin. As this would mean
some uglification, e.g.
# ifdef __cplusplus
# include <cstdio>
extern "C" {
# else
# include <stdio.h>
# endif
I can understand that the appropriate headers are not
included (ignoring the problem of knowing the appropriate
header for different C++ implementations).


Cheers
Michael
 
C

CBFalconer

C

CBFalconer

Michael said:
.... snip ...

As an aside: The only thing open to debate from a C point
of view is the question whether the header should contain
#include <stdio.h>
or not since it "uses" FILE and stdin. As this would mean
some uglification, e.g.
# ifdef __cplusplus
# include <cstdio>
extern "C" {
# else
# include <stdio.h>
# endif
I can understand that the appropriate headers are not
included (ignoring the problem of knowing the appropriate
header for different C++ implementations).

The header is not intended to enable compilation of ggets via a C++
compiler, but only the linkage to its code module from a C++
program.

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
K

Keith Thompson

Michael Mair said:
It definitely is valid as C90 or C99 + TC1 + TC2 code and
everything in between, with the stipulation for pre-C99
implementations that they must not define __cplusplus as
macro identifier.
If you have a pre-C99 implementation that does define
__cplusplus, then you will get a diagnostic ("compiler
error") from it.
[...]

Unless the implementation happens to support extern "C" as an
extension. I seriously doubt that any pre-C99 C implementations
define __cplusplus; if any did, they'd probably be trying to act like
C++ implementations, and would probably support extern "C".

Practically speaking, it's vanishingly unlikely to be a problem.
 
F

Frank Silvermann

Keith said:
Michael Mair said:
It definitely is valid as C90 or C99 + TC1 + TC2 code and
everything in between, with the stipulation for pre-C99
implementations that they must not define __cplusplus as
macro identifier.
If you have a pre-C99 implementation that does define
__cplusplus, then you will get a diagnostic ("compiler
error") from it.
[...]

Unless the implementation happens to support extern "C" as an
extension. I seriously doubt that any pre-C99 C implementations
define __cplusplus; if any did, they'd probably be trying to act like
C++ implementations, and would probably support extern "C".

Practically speaking, it's vanishingly unlikely to be a problem.
I've got a version from around '94 from the Evil Empire, and I believe
it ifdefs around the __cplusplus. The opportunity I see in this code
posting to have the languages talk to each other with less grief. For
me, I've been operating at the never_the_twain_shall_meet_below_the_OS
status for a while. I see a way to get results in the manner of Charles
Petzold without Appwizard removing my ability to debug. That's got too
sharp a tone to it on a day when Bill Gates announces he's gonna step
down. That's a tough day for a programmer. frank
 
O

Old Wolf

Michael said:
As an aside: The only thing open to debate from a C point
of view is the question whether the header should contain
#include <stdio.h>
or not since it "uses" FILE and stdin.

It doesn't use stdin, it contains a macro with stdin in it.
And you can forward-declare FILE on its own.
As this would mean
some uglification, e.g.
# ifdef __cplusplus
# include <cstdio>
extern "C" {
# else
# include <stdio.h>
# endif

#include said:
I can understand that the appropriate headers are not
included (ignoring the problem of knowing the appropriate
header for different C++ implementations).

Well, the C++ standard library has a function that does
the same as what ggets does. So I guess that ggets
would only be used by C++ programmers who do not
want to use the C++ standard library for some reason.
 
M

Michael Mair

Old said:
It doesn't use stdin, it contains a macro with stdin in it.

True, thus the "uses".
As soon as you just want to have, for example,

#include <stdlib.h>
#include "ggets.h"
#include "foo.h"

int main (void)
{
char *s = 0;
if (!ggets(&s)) {
foo *bar;
if (bar = calculateFoo(s)) {
outputFoo(bar);
freeFoo(bar);
}
}
free(s);
return 0;
}
you need to #include <stdio.h> even though you do not
obviously "need" it for using ggets(). This is ugly and
a "header defect" like this may not pass code review in
some companies.

And you can forward-declare FILE on its own.

How can you do so in standard C?
"FILE [...] is an object type capable of recording all the information
needed to control a stream, including its file position indicator,
a pointer to its associated buffer (if any), an error indicator that
records whether a read/write error has occurred, and an end-of-file
indicator that records whether the end of the file has been reached".
If the type were guaranteed to be a typedef for "struct _FILE_T", I'd
agree with you.
#include <stdio.h> is correct C++ code.

.... and deprecated. Why risk having to change all include
directives for "stdio" for a new compiler (version)?

Well, the C++ standard library has a function that does
the same as what ggets does. So I guess that ggets
would only be used by C++ programmers who do not
want to use the C++ standard library for some reason.

This is a very reasonable guess. Sometimes, people have
"good" reasons to do more or less unreasonable things,
though.


Cheers
Michael
 
M

Michael Mair

CBFalconer said:
Michael Mair wrote:

... snip ...


The header is not intended to enable compilation of ggets via a C++
compiler, but only the linkage to its code module from a C++
program.

I am aware of this; the ugliness in my opinion consists of
a header not bringing in everything necessary to use it.
The include problem is one reason why I still accept it as
is; another reason is that you usually need to explicitly
construct a situation where you use fggets()/ggets()
without having included <stdio.h>. The dependence between
the respective include directives still is not overly
joyous even if rules like "standard headers before library
headers before user headers" automatically fix the problem.
YMMV.


Cheers
Michael
 
C

CBFalconer

Michael said:
CBFalconer schrieb:
.... snip ...

I am aware of this; the ugliness in my opinion consists of
a header not bringing in everything necessary to use it.
The include problem is one reason why I still accept it as
is; another reason is that you usually need to explicitly
construct a situation where you use fggets()/ggets()
without having included <stdio.h>. The dependence between
the respective include directives still is not overly
joyous even if rules like "standard headers before library
headers before user headers" automatically fix the problem.

I disagree that stdio.h is needed to use ggets. The only thing
that might cause trouble is the definition of EOF in the return
value, but detection of a negative value suffices there. So the
using program need only include things that it itself needs. If it
needs the value of EOF, or an output routine, it must include
stdio.h for its own purposes.

The following should function anywhere:

#include <stdlib.h> /* for free */
#include "ggets.h" /* for ggets */

int main(void) {
char *line;

while (0 == ggets(&line) free(line);
return 0;
}

although there may be a difficulty with the value of 'stdin', which
is hidden in the ggets macro.
 
F

Frank Silvermann

CBFalconer said:
source has a comment about fixing the leak, to double check.
This reply relies on what I can do off-line, which is a nice way of
saying "becoming impatient while my news server pulls the moths out of
the vacuum tubes" I do have the revised version. You put:

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

in the header in such a manner that if some condition were true, then
any 'tja' within was going to get enclosed by extern "C" { tja } . In
the implementation file you have:


#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)

as the only instructions to the preprocessor, except the inclusion of
the header. When is it a good idea to have the preprocessor do the one
as opposed to the other, given that you want to write an ISO C module
that the other guys can access reliably? frank
 
C

CBFalconer

Frank said:
.... snip ...

This reply relies on what I can do off-line, which is a nice way of
saying "becoming impatient while my news server pulls the moths out
of the vacuum tubes" I do have the revised version. You put:

int fggets(char* *ln, FILE *f);

#define ggets(ln) fggets(ln, stdin)

in the header in such a manner that if some condition were true,
then any 'tja' within was going to get enclosed by extern "C" { tja }.

I have no idea what you mean by 'tja'. The wrapping in
extern "C" {
}
only occurs when used in a c++ compiler, and prevents the linkage
names being mauled. It does not happen when compiling ggets.o,
because ggets is a C module.
In the implementation file you have:

#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)

as the only instructions to the preprocessor, except the inclusion of
the header. When is it a good idea to have the preprocessor do the one
as opposed to the other, given that you want to write an ISO C module
that the other guys can access reliably? frank

Why would those go in the header? The headers ONLY purpose is to
export what is needed to link ggets into other modules. No other
module need know anything about those values, they are used only in
the ggets implementation. The preprocessor and the header files
have no special relationship.
 
K

Keith Thompson

CBFalconer said:
I disagree that stdio.h is needed to use ggets. The only thing
that might cause trouble is the definition of EOF in the return
value, but detection of a negative value suffices there. So the
using program need only include things that it itself needs. If it
needs the value of EOF, or an output routine, it must include
stdio.h for its own purposes.

The following should function anywhere:

#include <stdlib.h> /* for free */
#include "ggets.h" /* for ggets */

int main(void) {
char *line;

while (0 == ggets(&line) free(line);
return 0;
}

although there may be a difficulty with the value of 'stdin', which
is hidden in the ggets macro.

I'm not sure what you mean by "although there may be a difficulty".
With a "#include <stdio.h>", there's no problem with the *value* of
stdin, because it's an undeclared identifier. Likewise for FILE.

The expansion of #include "ggets.h" refers to the identifier FILE; the
expansion of ggets(&line) refers to the identifer stdin. How exactly
do you expect the compiler to resolve these identifiers without a
"#include <stdio.h>"?

(You also have a missing right parenthesis, corrected below).

% cat tmp.c
#include <stdlib.h> /* for free */
#include "ggets.h" /* for ggets */

int main(void) {
char *line;

while (0 == ggets(&line)) free(line);
return 0;
}
% gcc -c tmp.c
In file included from tmp.c:2:
ggets.h:37: error: syntax error before 'FILE'
tmp.c: In function 'main':
tmp.c:7: error: 'stdin' undeclared (first use in this function)
tmp.c:7: error: (Each undeclared identifier is reported only once
tmp.c:7: error: for each function it appears in.)

Adding a "#include <stdio.h>" to the top of tmp.c corrects the
problem, but the #include <stdio.h>" should be in "ggets.h".
 
F

Frank Silvermann

CBFalconer said:
Frank Silvermann wrote:
.... snip ...

I have no idea what you mean by 'tja'. The wrapping in
extern "C" {
}
only occurs when used in a c++ compiler, and prevents the linkage
names being mauled. It does not happen when compiling ggets.o,
because ggets is a C module.
There exists no ggets.o file in whatever I unzipped. One is left to
believe that '.o' is a typo or an intermediate file during
compiling-linking.
Why would those go in the header? The headers ONLY purpose is to
export what is needed to link ggets into other modules. No other
module need know anything about those values, they are used only in
the ggets implementation. The preprocessor and the header files
have no special relationship.
This last statement is a little shocking, but given the above-stated
purpose of a header and when you think about for a bit, quite true. frank
 
R

Randy Howard

Frank Silvermann wrote
(in article said:
There exists no ggets.o file in whatever I unzipped. One is left to
believe that '.o' is a typo or an intermediate file during
compiling-linking.

You are new to the C language, aren't you?
 
R

Richard Heathfield

Randy Howard said:
Frank Silvermann wrote

You are new to the C language, aren't you?

That's allowed. From what I've seen so far of Mr Silvermann, I have the
impression that he's fairly new to C but far from dense.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top