function calls, mandatory compiler promotion of int arguments tosize_t?

D

David Mathog

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);
}

The int variables size and count are both used for fwrite() arguments
which are prototyped to be size_t. If size_t is bigger than int (as on
some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
the C standard require the compiler to promote these two int values to
size_t before passing them to the function, and if so, what exactly does
it say?

I know that in _practice_ the code above works, but I am curious if that
must always be the case.

Thanks,

David Mathog
 
K

Keith Thompson

Eric Sosman said:
Yes, it is. Note that the prototype-governed conversions cut both
ways, though: If you pass a "wide" argument expression to a prototyped
function with a "narrower" parameter, the conversion from wide to narrow
may lose information silently.

Or it may give you some unexpected result. Conversion to a signed
integer type, if the value can't be represented in the target type,
yields an implementation-defined result (or raises an
implementation-defined signal; the latter is new in C99).
Similarly, if you pass a floating-point
argument to a prototyped integer parameter, the fractional part vanishes
silently. (There's the seedling of an IOCCC entry here, I think: try
`malloc(atan(42.0))' to allocate an 88-byte object ...)

For certain values of 42.0.

Actually, for *no* values of 42.0; the results of atan() are in the
range [-pi/2, +pi/2] (radians).

But tan(1.5595) would do it. Note that very small changes in the
argument result in large changes in the result.
 
K

Keith Thompson

Eric Sosman said:
Both of these qualify as "losing information," in my view.

But raising a signal doesn't necesssarily qualify as "silently".

[snip]
 
D

David Mathog

Eric said:
Tut. Tut, tut, tut. Consider your wrist slapped.

Exit status and error checking were intentionally sacrificed for a
shorter example program. I agree that real programs shouldn't do this,
but by going with "void main" and throwing out the one status value
returned the example program was able to drop a few lines which had
nothing to do with the question at hand.
Yes, and 6.5.2.2p7: "If the expression that denotes the called
function has a type that does include a prototype, the arguments are
implicitly converted, as if by assignment, to the types of the
corresponding parameters, taking the type of each parameter to be the
unqualified version of its declared type."

Perfect, that was exactly what I wanted to know.

Thanks,

David Mathog
 
B

Ben Bacarisse

David Mathog said:
Exit status and error checking were intentionally sacrificed for a
shorter example program.

In fact, C99 permits the return <exp>; to be omitted (zero is assumed)
so int main(void)... is even shorter (OK, by only one character) /and/
letter-of-the-law correct.
 
A

Antoninus Twink

Exit status and error checking were intentionally sacrificed for a
shorter example program. I agree that real programs shouldn't do this,
but by going with "void main" and throwing out the one status value
returned the example program was able to drop a few lines which had
nothing to do with the question at hand.

Unfortunately that won't wash with many of the "regulars" around here.
They don't know much about C, but they do have a religious zeal for
getting the return type of main "correct".

Many of them will try to argue that having void main there might have
everything to do with the question at hand, since according to clc dogma
it invokes UB, and they expect the compiler then to do everything in its
power to make your program go wrong.

The fact that this is complete nonsense in the real world means not a
whit to them.
 
V

vippstar

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);

}

The int variables size and count are both used for fwrite() arguments
which are prototyped to be size_t. If size_t is bigger than int (as on
some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
the C standard require the compiler to promote these two int values to
size_t before passing them to the function, and if so, what exactly does
it say?

You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);
I know that in _practice_ the code above works, but I am curious if that
must always be the case.

It doesn't, it's not.
 
S

santosh

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);

}

[ ... ]
You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);


It doesn't, it's not.

Does it _really_ fail if 'size' and 'count' are switched in this case?
Does the Standard say a call that interchanges these two arguments
_must_ be wrong? Beyond the difference in the return value, and it's
implications upon a partial write, which was recently discussed, what
difference would it actually make for fwrite itself whether it views
it's data as one element of N bytes or as N elements of one byte?
 
I

Ike Naar

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);

}
You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);

David Mathog's code writes one 27-byte chunk.
Yours writes 27 1-byte chunks.
Neither version is "wrong" per se.
 
V

vippstar

For this small test program:
#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);
}

[ ... ]
You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);
It doesn't, it's not.

Does it _really_ fail if 'size' and 'count' are switched in this case?
Does the Standard say a call that interchanges these two arguments
_must_ be wrong? Beyond the difference in the return value, and it's
implications upon a partial write, which was recently discussed, what
difference would it actually make for fwrite itself whether it views
it's data as one element of N bytes or as N elements of one byte?


They are both correct. However I was refering to 'void main()'.
(assuming hosted implementation)
 
B

Barry Schwarz

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);
}

The int variables size and count are both used for fwrite() arguments
which are prototyped to be size_t. If size_t is bigger than int (as on
some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
the C standard require the compiler to promote these two int values to
size_t before passing them to the function, and if so, what exactly does
it say?

As long as others have picked the nits, this is not a promotion in the
way the standard uses the term. It is a conversion as if by
assignment. If you change size and count to long and have a system
where size_t is unsigned int, the compiler is still required to
convert the arguments to the type expected by the called function
(even though it is a demotion).
 
S

santosh

For this small test program:
#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int
*/
count = 1; /* ditto
*/ (void) fwrite(buffer, size, count, stdout);

[ ... ]
I know that in _practice_ the code above works, but I am curious
if that must always be the case.
It doesn't, it's not.

Does it _really_ fail if 'size' and 'count' are switched in this
case? [ ... ]
They are both correct. However I was refering to 'void main()'.
(assuming hosted implementation)

Ah, OK. I failed to notice that error.
 
M

Martien Verbruggen

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);

}

The int variables size and count are both used for fwrite() arguments
which are prototyped to be size_t. If size_t is bigger than int (as on
some 64 bit systems where size_t is 8 bytes and int is 4 bytes), does
the C standard require the compiler to promote these two int values to
size_t before passing them to the function, and if so, what exactly does
it say?

You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);

How did you conclude that David meant to write 27 elements of 1 byte
each, rather than 1 element of 27 bytes? Or are you saying that it is
not possible to have an element of 27 bytes?

And what do you mean by 'misleading variable names'? The prototype for
fwrite is:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

(C99 adds some restricts in there as well),

So David's variable names match that quite well: 'size' for 'size' and
'count' for 'nmemb'. How is that misleading? Or is this simply a result
of your assumption that David swapped them around?

Martien
 
C

CBFalconer

blargg said:
.... snip ...

Sometimes UB like this is relevant to the person's question/problem
, so ignoring it might be ignoring the problem. Besides, it's an
easy fix and why not use the context as an opportunity to educate?


Either one is posting a compilable, runnable example, or one is
not. If not, why bother with #include <stdio.h>, or a main
function at all?

Ignoring the fact that Twink is a troll, if not posting a complete
compilable and runnable program, why bother posting at all? Think
of the electrons that could be saved. You will save time and be
able to contribute to PETE.
 
S

s0suk3

Sometimes UB like this is relevant to the person's question/problem, so
ignoring it might be ignoring the problem. Besides, it's an easy fix and
why not use the context as an opportunity to educate?


Either one is posting a compilable, runnable example, or one is not. If
not, why bother with #include <stdio.h>, or a main function at all?

It *is* compilable and runnable, but perhaps not with all compilers.
AFAIK, the standard states that an implementation may accept an
implementation-defined prototype for main(). I'd expect 'void
main(void)' to be a common choice for such prototype, seems it looks
fairly natural and is the one used in other languages.

Sebastian
 
S

santosh

(e-mail address removed) wrote:

AFAIK, the standard states that an implementation may accept an
implementation-defined prototype for main(). I'd expect 'void
main(void)' to be a common choice for such prototype, seems it looks
fairly natural and is the one used in other languages.

I would always return a sensible value back to the system. Returning
garbage values (which is what happens when you use void main) breaks
scripts and wrapper programs. Just return 0 or EXIT_FAILURE. Why is
this so hard?
 
R

Richard Bos

On Aug 3, 3:23 am, (e-mail address removed) (blargg) wrote:

It *is* compilable and runnable, but perhaps not with all compilers.

So is

int WINAPI WinMain(HINSTANCE instance, HINSTANCE previnst__,
PSTR cmdline, int showmode)

but you wouldn't recommend that as a sensible form of the main program
to be posted to this newsgroup, would you?

Richard
 
D

David Mathog

Then why the superfluous cast in the fwrite call?

(void) fwrite(buffer, size, count, stdout);

Tells the compiler (and anybody reading the program) that the return
value is intentionally being ignored. Leave that off and in their
pickier modes many compilers will issue a warning about the unused
return value.

Regards,

David Mathog
 
D

David Mathog

For this small test program:

#include <stdio.h>
void main(void){
char buffer[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
int size, count;
size = 27; /* always a small number which will fit in an int */
count = 1; /* ditto */
(void) fwrite(buffer, size, count, stdout);
You got good replies for these questions. Something I wanted to add is
that you got the order of size/nmemb arguments in the fwrite call
wrong; it's even harder to see that because of the misleading variable
names.
It should be
1 27
fwrite(buffer, count, size, stdout);

I know what you're saying, but in this instance I really did intend that
it be one big write. The example program was derived from a real one
where a large buffer had to be written entirely. Simplified a bit, the
original code was like this:

size=262144;
if(!fwrite(buffer,size,1,stdout)failure_function("message");

What you are saying is correct and useful if there is something to be
gained by knowing that 123456 out of 2626144 characters were written
before the output failed. In this instance a failure is a failure and
that extra information is not needed.

Regards,

David Mathog
 

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

No members online now.

Forum statistics

Threads
474,434
Messages
2,571,685
Members
48,796
Latest member
Greg L.

Latest Threads

Top