malloc() and implicit cast

E

Eric Sosman

What system are you using? I have never seen any system even suggest the
existence of an 'h' modifier in printf. There is one for scanf, but even
there, there's nothing suggesting that you could ever use more than one
of them.

ISO/IEC 9899:TC3 7.19.6.1p7 may merit your attention.
 
S

sandeep

Richard said:
Oh, there's an h modifier all right - see 4.9.6.1 of C89, or the C99
equivalent (fprintf docs).

But hh? I Don't Think So.

I think you are mistaken on this point Richard... Check out the man page.

The length modifier
Here, "integer conversion" stands for d, i, o, u, x, or X
conversion.

hh A following integer conversion corresponds to a signed
char or
unsigned char argument, or a following n conversion
corresponds
to a pointer to a signed char argument.

h A following integer conversion corresponds to a short
int or
unsigned short int argument, or a following n conversion
correâ€
sponds to a pointer to a short int argument.

l (ell) A following integer conversion corresponds to a
long int
or unsigned long int argument, or a following n conversion
corâ€
responds to a pointer to a long int argument, or a
following c
conversion corresponds to a wint_t argument, or a
following s
conversion corresponds to a pointer to wchar_t argument.

ll (ell-ell). A following integer conversion corresponds to a
long
long int or unsigned long long int argument, or a
following n
conversion corresponds to a pointer to a long long int
argument.

L A following a, A, e, E, f, F, g, or G conversion
corresponds to
a long double argument. (C99 allows %LF, but SUSv2 does
not.)

q ("quad". 4.4BSD and Linux libc5 only. Don't use.) This
is a
synonym for ll.

j A following integer conversion corresponds to an
intmax_t or
uintmax_t argument.

z A following integer conversion corresponds to a
size_t or
ssize_t argument. (Linux libc5 has Z with this meaning.
Don't
use it.)

t A following integer conversion corresponds to a ptrdiff_t
arguâ€
ment.
 
S

Seebs

ISO/IEC 9899:TC3 7.19.6.1p7 may merit your attention.

WTF. Clearly, I should add another hour or two to the "too early to post"
zone.

Obviously right -- interestingly, unmentioned in at least one bit of
documentation I have.

I guess my instinctive assumption that everything sandeep posts is nonsense
has gotten ahead of him.

-s
 
S

Seebs

I did better than that. I checked out the International Standard that
governs the language. In cases of discrepancy, it's the man page that
has got it wrong.

Maybe hh is new in C99? It's in C99.

I know it's unusual for sandeep to be right, but...

-s
 
K

Keith Thompson

Did you check the C99 standard?
You are mistaken to think I'm mistaken.

No, he's not.
I did better than that. I checked out the International Standard that
governs the language. In cases of discrepancy, it's the man page that
has got it wrong.

N1256 7.19.6.1p7:

The length modifiers and their meanings are:

hh Specifies that a following d, i, o, u, x, or X conversion
specifier applies to a signed char or unsigned char argument
(the argument will have been promoted according to the
integer promotions, but its value shall be converted to
signed char or unsigned char before printing); or that a
following n conversion specifier applies to a pointer to
a signed char argument.

The C99 standard also mentions the hh modifier; I presume the wording
is identical (there's no change bar in N1256), but I haven't bothered
to verify that.

C90 has "h" but not "hh".

Note that the "hh" modifier isn't really necessary here; a simple
"%d" would be sufficient (except perhaps on systems where char
promotes to unsigned int, which is possible only if plain char is
unsigned and CHAR_BIT >= 16).
 
K

Keith Thompson

sandeep said:
I still don't see why C lets you compile code correctly that will execute
incorrectly...

Because "correctness" is not something that a compiler can always
determine.

Would you expect a compiler to reject this?

#include <stdio.h>
int main(void)
{
puts("2 + 2 = 5");
return 0;
}
 
B

Barry Schwarz

?

The man page for printf on my system recommends hh modifier to print
integer value of a character. If you use %c then this will display it as
an ASCII character.

Obviously several people (me too) learned something new from this but
it seems there is no benefit from the modifier (yes, hh is a single
modifier). Furthermore, using it can lead to unexpected behavior.

First, let's eliminate the easy case. I don't see a use for %hhn (or
%hn) but the intent is clear. It will allow you to store the
character count into one of the lower ranking (and presumably shorter)
integer types. Maybe this is useful on an imbedded system with
extremely limited memory but would such a system even have a printf
function?

Second, you are passing a char (which will be converted to an int
before it is received). If the value is within the range of a signed
char, the value will be unchanged when printf converts it to signed
char. Printing this value will result in the exact same character
sequence by both %hhd and %d. Nothing is gained in this case. In the
case where char is unsigned, printf will still try to convert the
value back to a signed char. If the value does not fit, the next
paragraph applies.

But when a signed value (int or short) is passed that is not within
the range of signed char, printf's attempt to convert it to signed
char falls under the purview of 6.3.1.3-3.

In summary:

Since 255 is not a particularly long text sequence, %hhn is as
inherently unsafe as gets().

65,535 is probably adequate for most writes so an overflow with
%hn would be surprising.

Using %hhd or %hhi on anything other than a signed char puts the
program at risk and using it for a signed char does not provide any
benefit.

A similar situation holds for %hd and %hi. Using either with an
int or unsigned short value that does not fit in a signed short is
undesirable. If the value does fit, there is no benefit.

Slightly unrelated but can someone explain why converting an out of
range real floating value to integer produces undefined behavior but
doing the same to an out of range integer value produces "merely"
implementation defined behavior.
 
S

sandeep

Barry said:
Second, you are passing a char (which will be converted to an int before
it is received). If the value is within the range of a signed char, the
value will be unchanged when printf converts it to signed char.
Printing this value will result in the exact same character sequence by
both %hhd and %d. Nothing is gained in this case. In the case where
char is unsigned, printf will still try to convert the value back to a
signed char. If the value does not fit, the next paragraph applies.

I think you are mistaken on this point Barry.

Suppose you are on a system where int is 16 bits or more. Then if you
give a %d format specifier then passing the argument will read more than
one byte at the address of the character in memory. In this case that
will be disastrous as only 1 byte was malloc'd! However if you give %hhd
then only 1 byte is read from memory - then it gets promoted to int for
passing as an argument then implicitly typecast back down to char when
printf reads it.
 
E

Eric Sosman

I think you are mistaken on this point Barry.

Suppose you are on a system where int is 16 bits or more.

That is, suppose you are using C.
Then if you
give a %d format specifier then passing the argument will read more than
one byte at the address of the character in memory.

Nonsense. printf() never reads that character, and cannot
even discover where it is, or whether there ever was one.
In this case that
will be disastrous as only 1 byte was malloc'd!

Nonsense. printf() never reads anything from the allocated
memory, not one byte, not forty-two bytes.
However if you give %hhd
then only 1 byte is read from memory

Nonsense. printf() never reads anything from the allocated
memory, not one byte, not forty-two bytes.
- then it gets promoted to int for
passing as an argument then implicitly typecast back down to char when
printf reads it.

Nonsense. Too wearisome to explain (especially to someone who
almost certainly knows better and is probably trolling), but a review
of the "default argument promotions" seems in order.

You *did* get one thing right, though: You quoted no signatures.
Thank you.
 
B

Ben Bacarisse

sandeep said:
I think you are mistaken on this point Barry.

Suppose you are on a system where int is 16 bits or more. Then if you
give a %d format specifier then passing the argument will read more than
one byte at the address of the character in memory. In this case that
will be disastrous as only 1 byte was malloc'd! However if you give %hhd
then only 1 byte is read from memory - then it gets promoted to int for
passing as an argument then implicitly typecast back down to char when
printf reads it.

No, that's not how parameter passing works when the function is like
printf. All arguments after the format string get promoted (as Barry
has said) so both %d and %hhd will be working with an int. The
difference is only in how the int gets converted before printing.
 
K

Kenny McCormack

sandeep said:
I still don't see why C lets you compile code correctly that will execute
incorrectly...

#include <stdio.h>

int main(void) { puts("Your name is George"); }

This program compiles fine. But it is wrong. (My name isn't George)

--
No, I haven't, that's why I'm asking questions. If you won't help me,
why don't you just go find your lost manhood elsewhere.

CLC in a nutshell.
 
B

Barry Schwarz

I should have said "(whose value will be converted ..."
I think you are mistaken on this point Barry.

Suppose you are on a system where int is 16 bits or more. Then if you
give a %d format specifier then passing the argument will read more than
one byte at the address of the character in memory. In this case that

int must be at least 16 bits on a conforming system. However, the
char in question is not passed as if it were an int. Its value is
promoted to an int value and that is what is passed. The compiler
knows how to generate the promoted value without accessing any
unallocated bytes.
will be disastrous as only 1 byte was malloc'd! However if you give %hhd
then only 1 byte is read from memory - then it gets promoted to int for

While the compiler is allowed to examine the format string, it is not
required to do so. If the format string happens to be a variable that
is built at execution type (as opposed to a string literal), it may
not be possible for the compiler to examine it. Therefore, your
assertion that the format specification %hhd causes the compiler to
only examine one byte of the argument doesn't hold water. When the
compiler evaluates the argument, it knows that the argument is a char
and therefore only evaluates the byte which that char occupies. This
is no different than what happens when the format specification is %d
and the corresponding argument is a char. In both cases, the exact
same value is passed to printf.
passing as an argument then implicitly typecast back down to char when
printf reads it.

There is no such thing as an implicit cast. By definition, cast is an
explicit operator.

Furthermore, the standard does not require printf to be written in C.
It only requires the function to convert the value to signed char. So
your assumption that it uses a cast to perform this conversion is
unfounded.

Consider a common system with 8 bit bytes and char is unsigned. A
char could hold the value 255. This will be promoted to a signed int
value of 255. printf will attempt to convert this int value to a
signed char. It will not fit. You get an implementation defined
result or an implementation defined signal is raised. In either case,
printf will not print 255.
 
P

Phil Carmody

Seebs said:
What system are you using? I have never seen any system even suggest the
existence of an 'h' modifier in printf. There is one for scanf, but even
there, there's nothing suggesting that you could ever use more than one
of them.

WTF?

7.19.6.1 The fprintf function
....
[#7] The length modifiers and their meanings are:

hh Specifies that a following d, i, o, u, x, or X
conversion specifier applies to a signed char
or unsigned char argument (the argument will
have been promoted according to the integer
promotions, but its value shall be converted to
signed char or unsigned char before printing);
or that a following n conversion specifier
applies to a pointer to a signed char argument.

h Specifies that a following d, i, o, u, x, or X
conversion specifier applies to a short int or
unsigned short int argument (the argument will
have been promoted according to the integer
promotions, but its value shall be converted to
short int or unsigned short int before
printing); or that a following n conversion
specifier applies to a pointer to a short int
argument.
....
[#2] The printf function is equivalent to fprintf with the
argument stdout interposed before the arguments to printf.

I'm otherwise lost for words.
 
P

Phil Carmody

Richard Heathfield said:
Oh, there's an h modifier all right - see 4.9.6.1 of C89, or the C99
equivalent (fprintf docs).

But hh? I Don't Think So.

What's swallowed everyone's brains this week? (Or is it last week,
time's a blur currently.)

Please stop not thinking so, and please start reading.

Phil
 
S

Seebs


I'd never run into it, because it never came up -- since everything is
promoted anyway, the feature is of marginal utility. Then I checked
a single man page which didn't mention 'h'. (The man page was marginally
handier to me than the standard.)

-s
 
P

Phil Carmody

Richard Heathfield said:
You are way way way behind the curve. This issue was done, dusted, and
rehashed to death some time ago.

There is a fine distinction between "making a mistake" and "having
one's brains swallowed" that it may well benefit you to explore.

Yes, making a mistake about C is simple, and everyone does it
occasionally.

But presuming he was wrong, being ****-sure that you are right, not
being bothered or willing to check, and then asserting that he was
wrong So Fucking Arrogantly goes beyond just being a mistake. It's more
than the holes in your knowledge about C I'm shocked by here, it's
your attitude.

Phil
 
P

Phil Carmody

Richard Heathfield said:
Phil Carmody wrote:



Wrong. If I'd presumed he was wrong, I wouldn't have bothered to do
any checking at all.


Wrong. If I were ****-sure that I were right, I wouldn't have bothered
to do any checking at all.


Wrong. If I couldn't be bothered or were not willing to check, I
wouldn't have bothered to do any checking at all.

It falls to few men in clc to be so completely wrong as you have been
on this occasion.

Your checking is highly ineffectual, then. Please improve it.

Phil
 
B

blmblm

kenny's only caught the "to be a real man..." stuff recently

doesn't any of this apply to girls?

As someone lacking (as far as I know) a Y chromosome, I wonder that
too. But then I am a humorless feminist, apt to bristle at all kinds
of commonly-used phrases, from "separates the men from the boys" to
"you da man!" to "balls" used as roughly synonymous with "gumption"
to .... Well, that's probably enough, and this is off-topic anyway,
but maybe a belated two cents' worth from a "girl" are not entirely
amiss?
 
B

Barry Schwarz

The getchar line, marks the programmer
as somebody who doesn't know how to run their own programs
in a command line console outside of their IDE.

Would it have been better for the tutorial writer to assume the
existence of a hardware component called a console or a system feature
called a command line console or an implementation feature called an
IDE?
 
B

Barry Schwarz

Back to C: here is the first program I found in the first tutorial I
found on a search for "C programming".

#include <stdio.h>

int main()
{
printf( "I am alive! Beware.\n" );
getchar();
return 0;
}

I count five problems with it (*not* including the failure to check the
return value of printf). None of these is a showstopper (except possibly
the first, on ancient pre-ANSI compilers, which don't count), but they
are all style violations.

Did I miss any?

Why is not checking the return from printf anymore of an issue than
not checking the return from getchar? Is there any reasonable action
for the program to take if either returns an unexpected value?

Style violations??

1 - This thread is about malloc and the non-existent language feature
"implicit cast" yet the function in question does not relate to
either.

2 - The # is not in column 1.

3 - The lack of arguments for main should be explicitly declared with
void.

4 - The indentation should be larger,at least 4 (you never said whose
style).

5 - The exclamation point and the period in the string literal should
be reversed.

6 - A program should never wait for getchar() without a preceding
prompt telling the user what to do.
 

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
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top