is this declaration correct

E

Eric Sosman

Rather than
include <stdio.h> can I use int printf(const char *,...) correct at all
places if I only use printf in my program..

When I was very young and just getting started with my
first programming language -- FORTRAN II, it was -- I came
up with a way to avoid the IF statement by using a "computed
GO TO" instead. Wasn't I just the cleverest little precious
goody-smarts you can imagine?

Yes, you can write free-hand printf() declarations. It's
not as much of a challenge as doing without IF, but if it makes
you feel like a clever little precious goody-smarts, go ahead.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
On Wed, 18 Jul 2012 14:09:01 -0700, Keith Thompson wrote:
Rather than
include <stdio.h> can I use int printf(const char *,...) correct at all
places if I only use printf in my program..

You *can*, but there's no good reason to do so.
[30 lines deleted]
Just write "#include <stdio.h>" and be done with it.

Thanks for the informations. Conclusion seems to be that my definition
will work fine though may be sub-optimal.

That may be the conclusion that you drew, but it's certainly not
what I intended. More precisely, your statement is correct, but
not particularly useful.

In particular, if your implementation defines printf with the
"restrict" keyword, and you declare it without "restrict", it may
make your program's behavior undefined (I'd have to dig into the
wording in the standard to be sure). [snip]

Now that it is being pointed out, I'm confident you will
find the relevant passage or passages and post a correction.

Not exactly. [snip long and careful response]

I apologize. My response should have been more direct.

The declarations

int printf( const int *, ... );
int printf( const int * restrict, ... );

are interchangeable, for the same reason that the declarations

int foo( int );
int foo( const int );

are interchangeable. I had thought a hint would be enough to lead
you fairly immediately to the definition of type compatibility for
function types (which is 6.7.6.3 p15 in N1570). The last sentence
of that paragraph (unchanged since N1256) says

(In the determination of type compatibility and of a
composite type, each parameter declared with function or
array type is taken as having the adjusted type and each
parameter declared with qualified type is taken as having
the unqualified version of its declared type.)

Note the last part of the sentence, following 'and each'. I was
pretty sure you knew all this but had just forgotten, which is
why I chose a short, elliptical response. Again, my apologies.
So by declaring printf yourself (without the "restrict" rather
than including <stdio.h>, you are at worst invoking undefined
behavior, and at best depending on a potentially ambiguous line
of reasoning -- and imposing that line of reasoning on anyone who
reads or maintains the code.

I was meaning to argue that the behavior is in fact well-defined,
and unambiguously so. I think you'll agree that the sentence
quoted above shows that.
It *might* save some time by avoiding
having to process <stdio.h> (surely a tiny fraction of the time
we've spent debating it). And it doesn't extend to functions that
depend on the declaration of FILE.

Or you can just write "#include <stdio.h>", which is *much*
easier, guaranteed to be correct, and consistent with what 99%
of C programmers use and expect.

I pretty much agree with your style points, and said something
along similar lines in my direct response to OP. However, I think
the two questions (ie, is the declaration correct, and is it
stylistically advisable) should not be intertwined, but rather
addressed separately. Also, when one goal of the OP was to
limit the scope of where 'printf' is available, I think it is
worth observing that this goal can be met only by a stand-alone
declaration, without including <stdio.h>, even if we might
also want to offer a style opinion as to the advisability of
having such a goal in the first place. Really, all I'm advocating
is, give the technical answers first, and stylistic advice second
and separately.
 
T

Tim Rentsch

Phil Carmody said:
Tim Rentsch said:
Phil Carmody said:
also allows Principal of Data Hiding (localize
declaration to a block and prevent name leakage elsewhere).

That's not data hiding. That name is not permitted to exist anywhere
except as the standard library defines it, [snip[

That's not exactly right. Defining a library function (such
as printf()) yourself is undefined behavior, but the Standard
doesn't actually disallow it.

You're playing with the semantics of "disallow". I'm pretty sure
the standard doesn't disallow:

-- 8< -------
#!/usr/bin/perl
$_="krJhruaesrltre c a cnP,ohet";$_.=$1,print$2while s/(..)(.)//;
-- 8< -------

In fact, it looks like 5.1.1.3 specifically *allows* it, as it
defines part of the implementation's behaviour when fed such
a translation unit. (Either with or without the snip markers!)

However, such definitions of "allow", "disallow", "permit", etc.
are not useful except when playing games of language-lawyery,
in which case, we'd all up our pedantry.

I disagree, both generally for didactic reasons, and here
specifically for more practical reasons.

The general reasons are, basically, there are in fact some things
that the Standard disallows, and knowing that is a useful
distinction in certain cases. Glossing over the difference will
lead to trouble down the road; there are lots of things that are
just undefined behavior (as opposed to syntax errors or
constraint violations, which are truly disallowed), but in
practice some undefined behaviors are "more undefined" than
others. The grayness of this spectrum of various undefined
behaviors has a nice, sharp edge at one end, the point at which
certain program constructs are actually /not allowed/. It's
useful to keep that edge sharp in explanations, and conversely it
is confusing to blur it by labelling some undefined behaviors as
"disallowed". They are not disallowed, and it's a disservice to
the readers here to say they are.

The more specific reason is, not only is defining library
functions allowed (UB, but still allowed), this technique is
actually used on occasion in implementations that support it.
Calling it disallowed leads to an impossible world model,
contradicted by actual working (and conforming) programs
that make use of it.

Certainly I am not above making a pedantic comment. In this
case, however, it is not pedantry, but rather a conern for
the understanding of those who are new to these concepts
and find them confusing enough even without any blurring,
that prompts me to point out the distinctions here.
 
T

Tim Rentsch

Phil Carmody said:
4b. Ignore the scare tactics of those who tell you, once you've
included stdlib.h, to write:

type_t *p = malloc(sizeof(*p));

rather than:

type_t *p = (type_t *)malloc(sizeof(type_t));

The former is absolutely guaranteed to work.

Good advice, no?

The scare tactics I was referring to (ie, for declaring printf)
were allusions to things _that cannot happen_. Casting the
result of malloc() can cause real problems, and, AFAIAA, actually
does cause problems in some implementations (if stdlib.h has not
been included). There's a difference between, on the one hand,
accurately reporting a problem that's actually been observed (in
the case of malloc()), and on the other hand alluding to possible
problems that have never been observed, and even in some cases
cannot be observed because the underlying assumptions are wrong.
It's only the second of these that fall under the label of "scare
tactics", as I was intending the term.
I'm tempted to say a cost-risk-benefit analysis
would favour my advice even more than yours, given what I've
actually seen go wrong over the decades. E.g. gcc's format mismatch
warnings trap many portability gotchas as well as grosser bugs -
cost zero, risk zero, benefit palpable.

Are you assuming that arguments to printf() are diagnosed (with
warning messages) only if <stdio.h> is included? The gcc that I
have diagnoses printf() arguments whether or not the header is
included (given suitable compiler option switches, obviously).

I'm not opposed to offering style advice. However, I think it
should be presented as such, and always should reflect _actual_
potential concerns, not _imagined_ concerns that either have no
basis in actual experience or, even worse, misrepresent how the
language is defined and what it is required to do. I don't think
the misrepresentations in this thread were intentional, but I do
think there were misrepresentations, and they deserve to be
called out as such. So I don't think it's wrong to label them
as "scare tactics".
 
K

Keith Thompson

Tim Rentsch said:
Keith Thompson said:
Tim Rentsch said:
On Wed, 18 Jul 2012 14:09:01 -0700, Keith Thompson wrote:
Rather than
include <stdio.h> can I use int printf(const char *,...) correct at all
places if I only use printf in my program..

You *can*, but there's no good reason to do so.
[30 lines deleted]
Just write "#include <stdio.h>" and be done with it.

Thanks for the informations. Conclusion seems to be that my definition
will work fine though may be sub-optimal.

That may be the conclusion that you drew, but it's certainly not
what I intended. More precisely, your statement is correct, but
not particularly useful.

In particular, if your implementation defines printf with the
"restrict" keyword, and you declare it without "restrict", it may
make your program's behavior undefined (I'd have to dig into the
wording in the standard to be sure). [snip]

Now that it is being pointed out, I'm confident you will
find the relevant passage or passages and post a correction.

Not exactly. [snip long and careful response]

I apologize. My response should have been more direct.

The declarations

int printf( const int *, ... );
int printf( const int * restrict, ... );

(You mean const char *, not const int *, yes?)
are interchangeable, for the same reason that the declarations

int foo( int );
int foo( const int );

are interchangeable. I had thought a hint would be enough to lead
you fairly immediately to the definition of type compatibility for
function types (which is 6.7.6.3 p15 in N1570). The last sentence
of that paragraph (unchanged since N1256) says

(In the determination of type compatibility and of a
composite type, each parameter declared with function or
array type is taken as having the adjusted type and each
parameter declared with qualified type is taken as having
the unqualified version of its declared type.)

Thanks, I should have found that myself.

But look at 6.7.6p2:

Each declarator declares one identifier, and asserts that
when an operand of the same form as the declarator appears
in an expression, it designates a function or object with the
scope, storage duration, and type indicated by the declaration
specifiers.

The types of

int printf( const char *, ... );
int printf( const char * restrict, ... );

are *compatible*, but they aren't *the same*, which is what 6.7.6p2
requires.

6.7.6p2 says that the declaration "asserts" that they're the same
type. It doesn't directly say what happens if that assertion fails;
I presume the behavior is undefined.

Is there a clearer statement about the requirement for declarations to
match definitions? For example, if I declare

int printf(const char*); /* note: non-variadic */

and then call printf("Hello, world\n"), the behavior is undefined; is
this explicitly stated somewhere?

[...]
I pretty much agree with your style points, and said something
along similar lines in my direct response to OP. However, I think
the two questions (ie, is the declaration correct, and is it
stylistically advisable) should not be intertwined, but rather
addressed separately. Also, when one goal of the OP was to
limit the scope of where 'printf' is available, I think it is
worth observing that this goal can be met only by a stand-alone
declaration, without including <stdio.h>, even if we might
also want to offer a style opinion as to the advisability of
having such a goal in the first place. Really, all I'm advocating
is, give the technical answers first, and stylistic advice second
and separately.

Ok, but I think the stylistic advice is important in this case. My
impression of your response to the OP was that didn't sufficiently
emphasize that part.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
On Wed, 18 Jul 2012 14:09:01 -0700, Keith Thompson wrote:
Rather than
include <stdio.h> can I use int printf(const char *,...) correct at all
places if I only use printf in my program..

You *can*, but there's no good reason to do so.
[30 lines deleted]
Just write "#include <stdio.h>" and be done with it.

Thanks for the informations. Conclusion seems to be that my definition
will work fine though may be sub-optimal.

That may be the conclusion that you drew, but it's certainly not
what I intended. More precisely, your statement is correct, but
not particularly useful.

In particular, if your implementation defines printf with the
"restrict" keyword, and you declare it without "restrict", it may
make your program's behavior undefined (I'd have to dig into the
wording in the standard to be sure). [snip]

Now that it is being pointed out, I'm confident you will
find the relevant passage or passages and post a correction.

Not exactly. [snip long and careful response]

I apologize. My response should have been more direct.

The declarations

int printf( const int *, ... );
int printf( const int * restrict, ... );

(You mean const char *, not const int *, yes?)

Yes I did, thank you (although it doesn't change the point about
using 'restrict').
Thanks, I should have found that myself.

But look at 6.7.6p2:

Each declarator declares one identifier, and asserts that
when an operand of the same form as the declarator appears
in an expression, it designates a function or object with the
scope, storage duration, and type indicated by the declaration
specifiers.

The types of

int printf( const char *, ... );
int printf( const char * restrict, ... );

are *compatible*, but they aren't *the same*, which is what 6.7.6p2
requires.

The key question here is what type is "indicated". The answer to
that is specified in 6.2.7 p4:

For an identifier with internal or external linkage declared
in a scope in which a prior declaration of that identifier
is visible, if the prior declaration specifies internal or
external linkage, the type of the identifier at the later
declaration becomes the composite type.

Note that the last sentence of 6.7.6.3 p15 also applies to the
formation of the composite type in this case.
6.7.6p2 says that the declaration "asserts" that they're the same
type. It doesn't directly say what happens if that assertion fails;
I presume the behavior is undefined.

The type being asserted simply changes as the program text
proceeds. I don't think there is anything very mysterious
about this. If we have code like

int a[];
...
a[0] = 0;
...
int a[10];
a[0] = 1;

the type of 'a' is incomplete at the first assignment, and
complete at the second assignment. There is nothing that
requires these two types to be the same; each declarator
asserts what it asserts until (possibly) changed by a
subsequent declarator.
Is there a clearer statement about the requirement for declarations to
match definitions? For example, if I declare

int printf(const char*); /* note: non-variadic */

and then call printf("Hello, world\n"), the behavior is undefined; is
this explicitly stated somewhere?

The call is UB because of 6.5.2.3 p9.

The declaration is UB because of 6.2.7 p2.

Because printf() is called, 6.9 p5 requires that printf() be
defined (or else UB).

Of course, there is the question of how printf() is defined,
hosted implementation, yada yada yada. But you know all
that.
Ok, but I think the stylistic advice is important in this case. My
impression of your response to the OP was that didn't sufficiently
emphasize that part.

I am perfectly okay with different people having different opinions
on points of style. Generally I try to avoid style battles whenever
possible. What bothered me, I think, was so many people focusing on
the style concerns at the expense of what the OP really was trying to
ask about. I feel like his questions, and what intentions motivated
those questions, got lost in the noise of giving style advice. As
long as that point is addressed, clearly and distinctly, I'm okay
with however much emphasis people want to give on the style issues;
in fact how much style concerns are emphasized is itself a kind of
style issue. On this particular issue I think our goals are actually
not that far apart; where we may differ is in what approach will
most help achieve those goals. You might be interested to know that
partly I was inspired by an aphorism from another posting of yours
(on a different topic, not that that matters), which was "when in
doubt, learn the rules, thereby removing the doubt" (or something
along those lines anyway). I think that's an excellent aphorism,
and was pleased that OP had (unconsciously) adopted it.

I hope you've enjoyed my comments even if we haven't yet
reached 100% agreement.
 
P

Phil Carmody

Tim Rentsch said:
The scare tactics I was referring to (ie, for declaring printf)
were allusions to things _that cannot happen_. Casting the
result of malloc() can cause real problems, and, AFAIAA, actually
does cause problems in some implementations (if stdlib.h has not
been included). There's a difference between, on the one hand,
accurately reporting a problem that's actually been observed (in
the case of malloc()), and on the other hand alluding to possible
problems that have never been observed, and even in some cases
cannot be observed because the underlying assumptions are wrong.
It's only the second of these that fall under the label of "scare
tactics", as I was intending the term.


Are you assuming that arguments to printf() are diagnosed (with
warning messages) only if <stdio.h> is included? The gcc that I
have diagnoses printf() arguments whether or not the header is
included (given suitable compiler option switches, obviously).

That surprises me, but it appears to be true. I had assumed that as
the .h files were decorated, the compiler knew of these properties
only because of the decoration. Clearly I had ASSumed incorrectly. As
I say, I find that surprising, and I don't like my compiler surprising
me, even when it's trying to be helpful. Whether it's also true about
all the insights that the #include gives, I don't know.
I'm not opposed to offering style advice. However, I think it
should be presented as such, and always should reflect _actual_
potential concerns, not _imagined_ concerns that either have no
basis in actual experience or, even worse, misrepresent how the
language is defined and what it is required to do. I don't think
the misrepresentations in this thread were intentional, but I do
think there were misrepresentations, and they deserve to be
called out as such. So I don't think it's wrong to label them
as "scare tactics".

OK, accepted.

Phil
--
I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
 
B

Ben Bacarisse

Eric Sosman said:
When I was very young and just getting started with my
first programming language -- FORTRAN II, it was -- I came
up with a way to avoid the IF statement by using a "computed
GO TO" instead. Wasn't I just the cleverest little precious
goody-smarts you can imagine?

Yes, you can write free-hand printf() declarations. It's
not as much of a challenge as doing without IF, but if it makes
you feel like a clever little precious goody-smarts, go ahead.

Oh, please! I don't get any sense that the OP is revelling in having
"discovered" something smart.

There are lots motivations for posting a question like this, including
sounds pedagogic ones. It's true that the OP has not posted back to say
"OK, I'll never do that" but I think there's a good reason for that:
this very question (right down to the quote from Stroustrup) has been
posted here many times -- at least in 2001 and again in 2010. It's
almost certainly homework, and the OP's summary ("It's legal but not
optimal") is probably the answer he's going to submit.
 
B

Ben Bacarisse

Tim Rentsch said:
Not that this matters really, but historically the Law of Least
Astonishment (as it used to be called) arose in connection with
the design of programming languages rather than the design of
programs (assuming my memory on the subject is correct, which it
may not be). So the allusion to it here caused (for me at least)
the more general principle to be violated.

I'm not a fan of rules and laws (who's in charge of them anyway). It
was just as way to say "try to avoid oddities" -- little more than a
slightly specific form of the vague advice to write clear code.
Will it? If I saw a local declaration of printf(), I think I
would assume the writer wanted to limit the scope of where the
identifier will be used, just like any other declaration. Is
there reason to believe his readers are confused on this point?
I don't see any reason a priori to expect they will be.

Well, it would surprise me. (I did not say "confuse", though I accept
that the distinction is small but it's not insignificant). I'd wonder
why. Is the author doing some trick to use printf for some other
purpose in other scopes? Some of these could be causing a problem (UB)
so I might waste time checking to be sure.
Oh, but his question is a little bit different, namely, is this
the right way to write the declaration?

And I answered that some time ago with a clear "yes". The discussion
has moved on (or at least I thought it had) to the merits of doing this,
rather than it's correctness.
The readers don't need
to worry (and probably won't worry) about that question, since
he is giving them (presumably) a working program.

I often end up looking at code because it's not working. If everyone
only ever looked at code that works, programming guidelines would be
very different, I think. The need for clarity would be driven mainly by
the desire to facilitate improvements and modifications rather than to
save time when chasing down porting bugs.
It's possible
of course that some of them will wonder about whether it's legal,
and take the trouble to find out, but that doesn't strike me as
a bad thing; it's only when unwary readers are confused that I
think some sort of advisory is called for, but to me that doesn't
seem to be the case here.

This puzzles me a bit. Taken in abstract, I can't form any view of who
might end up reading code, written by the OP, based on this advice.

Taken in context, I don't think it matters since the post is almost
certainly coursework. Exactly this question has been posted here at
least three times since 2001. In light of that, the OP's summary --
"correct by not optimal" -- is not a bad answer in my view.
 
K

Keith Thompson

Tim Rentsch said:
The call is UB because of 6.5.2.3 p9.

You mean 6.5.2.2 p9.

If the function [in a function call] is defined with a type
that is not compatible with the type (of the expression)
pointed to by the expression that denotes the called function,
the behavior is undefined.
The declaration is UB because of 6.2.7 p2.

All declarations that refer to the same object or function
shall have compatible type; otherwise, the behavior is undefined.
Because printf() is called, 6.9 p5 requires that printf() be
defined (or else UB).

An *external definition* is an external declaration that is also
a definition of a function (other than an inline definition)
or an object. If an identifier declared with external linkage
is used in an expression (other than as part of the operand
of a sizeof or _Alignof operator whose result is an integer
constant), somewhere in the entire program there shall be
exactly one external definition for the identifier; otherwise,
there shall be no more than one.

(Providing copy-and-paste for the benefit of those who don't want to
take the time to look up the references -- though I suspect the
intersection with the set of those who are still following this may be
very small.)

[...]
I am perfectly okay with different people having different opinions
on points of style. Generally I try to avoid style battles whenever
possible. What bothered me, I think, was so many people focusing on
the style concerns at the expense of what the OP really was trying to
ask about. I feel like his questions, and what intentions motivated
those questions, got lost in the noise of giving style advice. As
long as that point is addressed, clearly and distinctly, I'm okay
with however much emphasis people want to give on the style issues;
in fact how much style concerns are emphasized is itself a kind of
style issue. On this particular issue I think our goals are actually
not that far apart; where we may differ is in what approach will
most help achieve those goals. You might be interested to know that
partly I was inspired by an aphorism from another posting of yours
(on a different topic, not that that matters), which was "when in
doubt, learn the rules, thereby removing the doubt" (or something
along those lines anyway). I think that's an excellent aphorism,
and was pleased that OP had (unconsciously) adopted it.

That's pretty cool; I forget that I had written that. :cool:}

On the other hand, I've sometimes offered contrary advice.
For example, I find it easier to avoid defining identifiers starting
with underscores than to keep track of the cases where they can be
defined safely. And similarly, I'd rather #include standard headers
(and advise others to do so) than figure out when and whether I
can safely declare standard functions myself.

I mentioned recently that the C standard library is not a model of
consistency. I follow in its footsteps.
I hope you've enjoyed my comments even if we haven't yet
reached 100% agreement.

Absolutely.
 
S

Seungbeom Kim

Actually what he wants is to _limit_ the visibility to something
smaller than file scope. To do that, it is necessary to declare
printf() directly, since doing a #include has defined behavior only
outside of all external defintions (and in particular, outside of
any function body).

Why would anyone want to limit the visibility of library entities
to something smaller than file scope? What benefits would it bring
to make printf() visible to a function but not to anything else?
It's not as if you'd want to hide printf() from clients and expose
it only through some controlled interface so that it could be modified
without affecting the clients -- it's a part of the interface already!
 
P

Philip Lantz

Keith Thompson wrote:
....
(Providing copy-and-paste for the benefit of those who don't want
to take the time to look up the references -- though I suspect the
intersection with the set of those who are still following this may
be very small.)

It may be small, but it's not empty! Thanks!
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
The call is UB because of 6.5.2.3 p9.

You mean 6.5.2.2 p9.

If the function [in a function call] is defined with a type
that is not compatible with the type (of the expression)
pointed to by the expression that denotes the called function,
the behavior is undefined.

Quite right, thank you. I looked at the section number at
the bottom of the page, which unfortunately reflected the
next section rather than the one I was reading.
 
T

Tim Rentsch

Ben Bacarisse said:
I'm not a fan of rules and laws (who's in charge of them anyway).

My point was to reference the person who originally articulated
the principle mentioned and use the name he used to describe it,
not to mention the the actual principle. I guess you meant
something else, and I didn't mean to try to change and/or label
that, but then there is some confusion about what principle you
mean, and therefore whether it's something I would agree with...
It was just as way to say "try to avoid oddities" -- little
more than a slightly specific form of the vague advice to write
clear code.

I don't disagree, but I'm not sure this has much more meaning
than saying write clear code, and also doesn't match (for me
anyway) the principle, or I should say the name you gave to
the principle, because now I don't know what principle you
meant.

Well, it would surprise me. (I did not say "confuse", though I accept
that the distinction is small but it's not insignificant). I'd wonder
why. Is the author doing some trick to use printf for some other
purpose in other scopes? Some of these could be causing a problem (UB)
so I might waste time checking to be sure.

I'm sure this says something about one of us, but I'm not sure
whether it's you or me. :)
And I answered that some time ago with a clear "yes". The discussion
has moved on (or at least I thought it had) to the merits of doing this,
rather than it's correctness.

Some confusion there, I may be mostly to blame for it. When
I said "right" I didn't mean "legal", but more in the sense
of "appropriate". I think there are cases when it's appropriate
to write function declarations in that way, and that's what I
thought hadn't been addressed.

I often end up looking at code because it's not working. If everyone
only ever looked at code that works, programming guidelines would be
very different, I think. The need for clarity would be driven mainly by
the desire to facilitate improvements and modifications rather than to
save time when chasing down porting bugs.

Does this mean you're presuming (at least provisionally) he's
giving you non-working code, and commenting accordingly? Do
you give different comments if you're critiquing working code?

This puzzles me a bit. Taken in abstract, I can't form any view of who
might end up reading code, written by the OP, based on this advice.

Taken in context, I don't think it matters since the post is almost
certainly coursework. Exactly this question has been posted here at
least three times since 2001. In light of that, the OP's summary --
"correct by not optimal" -- is not a bad answer in my view.

That's funny, because if I were sure it were homework I would
give a very different answer. (I am one of those people who
actually looked up the word "gullible" upon hearing that it
isn't in the dictionary...)
 
T

Tim Rentsch

Seungbeom Kim said:
Why would anyone want to limit the visibility of library entities
to something smaller than file scope? What benefits would it bring
to make printf() visible to a function but not to anything else?

For the same reason that limiting visibility is always done, or
at least one of the same reasons, namely, to make sure it isn't
accidentally referenced somewhere it shouldn't be.
It's not as if you'd want to hide printf() from clients and expose
it only through some controlled interface so that it could be modified
without affecting the clients -- it's a part of the interface already!

Can you not imagine any scenario when someone might want to call
printf() from one function, or a small number of functions, but
not elsewhere? Try this one: you're writing a set of library
functions, let's set a compacting storage allocator. The source
includes some test code (suitably ifdef'able) in the same source
files as the library functions. For test purposes we would like
to print out some information, eg, call printf(). But printf()
should never be used in the actual library functions; indeed,
maybe it cannot be because the program is supposed to run on an
embedded system. Using local declarations, the test functions
can call printf(), but there is no contamination of the general
file-level scope. Granted, this may not be a common use case,
but it seems like a perfectly reasonable one.
 
K

Keith Thompson

Tim Rentsch said:
Can you not imagine any scenario when someone might want to call
printf() from one function, or a small number of functions, but
not elsewhere? Try this one: you're writing a set of library
functions, let's set a compacting storage allocator. The source
includes some test code (suitably ifdef'able) in the same source
files as the library functions. For test purposes we would like
to print out some information, eg, call printf(). But printf()
should never be used in the actual library functions; indeed,
maybe it cannot be because the program is supposed to run on an
embedded system. Using local declarations, the test functions
can call printf(), but there is no contamination of the general
file-level scope. Granted, this may not be a common use case,
but it seems like a perfectly reasonable one.

Is there such a scenario where it would be difficult to put the
test code in a separate source file?
 
T

Tim Rentsch

Keith Thompson said:
Is there such a scenario where it would be difficult to put the
test code in a separate source file?

Sure. When it needs to access 'static' variables in
the source.
 
I

Ian Collins

Sure. When it needs to access 'static' variables in
the source.

You should always be able to decouple the test code from the source.

The tests should not have direct access to the internals of the
functions being tested. If they do, the tests are too tightly coupled,
testing the implementation rather than the behaviour of the functions.
This coupling leads to fragile tests that preclude refactoring of the
tested code.
 
T

Tim Rentsch

Ian Collins said:
Keith Thompson said:
[...]
Can you not imagine any scenario when someone might want to call
printf() from one function, or a small number of functions, but
not elsewhere? Try this one: you're writing a set of library
functions, let's set a compacting storage allocator. The source
includes some test code (suitably ifdef'able) in the same source
files as the library functions. For test purposes we would like
to print out some information, eg, call printf(). But printf()
should never be used in the actual library functions; indeed,
maybe it cannot be because the program is supposed to run on an
embedded system. Using local declarations, the test functions
can call printf(), but there is no contamination of the general
file-level scope. Granted, this may not be a common use case,
but it seems like a perfectly reasonable one.

Is there such a scenario where it would be difficult to put the
test code in a separate source file?

Sure. When it needs to access 'static' variables in
the source.

You should always be able to decouple the test code from the source.

The tests should not have direct access to the internals of the
functions being tested. If they do, the tests are too tightly
coupled, testing the implementation rather than the behaviour of the
functions. This coupling leads to fragile tests that preclude
refactoring of the tested code.

I didn't mean to start a debate on the relative merits of
black box testing versus white box testing. Obviously this
is a big topic and there are proponents of various different
strategies.

However, when making a decision about the capabilities of our
testing framework, it seems wrong to adopt an approach that
excludes the possibility of a widely used testing methodology.
Even if we think that 99 times out of 100 it's better to use
black box testing than white box testing, we don't want to have
to go outside the normal testing framework for the other cases.
No matter which methodology is preferred, the framework should
accommodate other possibilities, not foreclose them.
 
P

Phil Carmody

Tim Rentsch said:
For the same reason that limiting visibility is always done, or
at least one of the same reasons, namely, to make sure it isn't
accidentally referenced somewhere it shouldn't be.


Can you not imagine any scenario when someone might want to call
printf() from one function, or a small number of functions, but
not elsewhere? Try this one: you're writing a set of library
functions, let's set a compacting storage allocator. The source
includes some test code (suitably ifdef'able) in the same source
files as the library functions. For test purposes we would like
to print out some information, eg, call printf(). But printf()
should never be used in the actual library functions; indeed,
maybe it cannot be because the program is supposed to run on an
embedded system. Using local declarations, the test functions
can call printf(), but there is no contamination of the general
file-level scope. Granted, this may not be a common use case,
but it seems like a perfectly reasonable one.

Why is printf at file scope considered such an undesirable
"contamination" in the case where the #if'ed test code is active?
You've contaminated the library with all the test functions already,
and even with local declarations you still cause the linker to link
your lib file to the stdio implementation library. I can't see why a
file-scope printf symbol would be a straw that breaks any particular
camel's back.

Phil
 

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,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top