malloc() and implicit cast

S

sandeep

I have checked the FAQ: http://c-faq.com/malloc/mallocnocast.html

FAQ discusses a special case when programmer has forgotten to do
#include <stdlib.h>. I am including this header and I am not doing any
explicit cast:

#include<stdlib.h>

enum ARRSIZE { MAXSIZE = 100 };

struct dummy
{
int i;

};

int main( void )
{

char *pc;
struct dummy *ptrDummy;

pc = malloc( MAXSIZE );
ptrDummy=malloc(sizeof(struct dummy));

return 0;

}

============ OUTPUT ============
/home/sandeep/programs/C $ gcc -ansi -pedantic -Wall -Wextra test.c
/home/sandeep/programs/C $ ./a.out
/home/sandeep/programs/C $

malloc(size_t n) returns a void pointer and here in my program, I am
assigning malloc returned pointers to 2 different types and I am not
getting any warnings about <implicit cast>.

It has something to do with C90 ?
 
M

mohangupta13

I have checked the FAQ:  http://c-faq.com/malloc/mallocnocast.html

FAQ discusses a special case when programmer has forgotten to do
#include <stdlib.h>. I am including this header and I am not doing any
explicit cast:

#include<stdlib.h>

enum ARRSIZE { MAXSIZE = 100 };

struct dummy
{
  int i;

};

int main( void )
{

  char *pc;
  struct dummy *ptrDummy;

  pc = malloc( MAXSIZE );

how is MAXSIZE used without declaring a variable of the enum type
ARRSIZE...i mean is it allowed (it looks from the example)and if so
then why?
 
B

Ben Pfaff

mohangupta13 said:
how is MAXSIZE used without declaring a variable of the enum type
ARRSIZE...i mean is it allowed (it looks from the example)and if so
then why?

Members of enumerations just have type "int". You can use them
wherever you can use an int literal.
 
K

Keith Thompson

sandeep said:
I have checked the FAQ: http://c-faq.com/malloc/mallocnocast.html

FAQ discusses a special case when programmer has forgotten to do
#include <stdlib.h>. I am including this header and I am not doing any
explicit cast:

#include<stdlib.h>

enum ARRSIZE { MAXSIZE = 100 };

Since you don't use the tag ARRSIZE, you can omit it:

enum { MAXSIZE = 100 };

Since someone else asked about this, it's a fairly common trick for
declaring a constant of type int. One drawback is that it's something
of an abuse of the "enum" feature, using for a purpose for which it
wasn't really intended, but personally I have no problem with that.
Another is that it can only be used to declare constants of type int.

An object declared to be of type "enum ARRSIZE" is, obviously,
of type "enum ARRSIZE", but surprisingly the constant MAXSIZE is
of type int. That's just one of C's historical oddities.

One alternative is:

#define MAXSIZE 100

which is fairly common, but it's usually good to avoid using the
preprocessor unless you really need it (I suspect this will trigger a
long discussion).

Another is

const int MAXSIZE = 100;

but that doesn't create an actual constant; for example, you couldn't
use MAXSIZE as a case label. It's ok in this case, but the enum
trick avoids that issue (while, as I said, restricting the type
to int).
struct dummy
{
int i;

};

int main( void )
{

char *pc;
struct dummy *ptrDummy;

pc = malloc( MAXSIZE );
ptrDummy=malloc(sizeof(struct dummy));

return 0;

} [...]
malloc(size_t n) returns a void pointer and here in my program, I am
assigning malloc returned pointers to 2 different types and I am not
getting any warnings about <implicit cast>.

Correct. An expression of type void* may be implicitly converted to any
pointer type (other than a pointer-to-function type), and vice versa.
It has something to do with C90 ?

I'd say rather that it has something to do with C. The ANSI C89
standard, which is equivalent to the ISO C90 standard, introduced the
void keyword, the void* type, and the rules for implicit conversion.
Some pre-C90 implementations may have behaved differently, but
you're unlikely to have to use anything that old.

One final note: *There is no such thing as an "implicit cast"*.
A "cast" is an operator, represented as a parenthesized type name
preceding an expression. A "conversion" is the operation specified
by the cast operator. A conversion can be either explicit (specified
by a cast operator) or implicit, but a cast can only be explicit.

<OT>C++ has several significant differences from C in these areas.</OT>
 
S

sandeep

Keith said:
Correct. An expression of type void* may be implicitly converted to any
pointer type (other than a pointer-to-function type), and vice versa.

so an int* is implicitly converted to a void* which then can be
implicitly converted to char* without any warning at all.
I'd say rather that it has something to do with C. The ANSI C89
standard, which is equivalent to the ISO C90 standard, introduced the
void keyword, the void* type, and the rules for implicit conversion.
Some pre-C90 implementations may have behaved differently, but you're
unlikely to have to use anything that old.

One final note: *There is no such thing as an "implicit cast"*. A "cast"
is an operator, represented as a parenthesized type name preceding an
expression. A "conversion" is the operation specified by the cast
operator. A conversion can be either explicit (specified by a cast
operator) or implicit, but a cast can only be explicit.

<OT>C++ has several significant differences from C in these areas.</OT>

--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/
~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

so I conlcude:

1.) Function Pointers: pointer to function returning an int can be
implicitly converted into char* without any any warning message.

2.) Pointers to object types: compiler can implicitly convert and int*
into char* without any warning message to the programmer. C doe snot
require any warning in this case

Is that what you mean?
 
K

Keith Thompson

sandeep said:
so an int* is implicitly converted to a void* which then can be
implicitly converted to char* without any warning at all.

Correct, and yes, that's potentially dangerous.

Please don't quote signatures.
so I conlcude:

1.) Function Pointers: pointer to function returning an int can be
implicitly converted into char* without any any warning message.

No. As I said in a paragraph that you snipped, the implicit
conversion of void* does not apply to pointer-to-function types.
2.) Pointers to object types: compiler can implicitly convert and int*
into char* without any warning message to the programmer. C doe snot
require any warning in this case

Correct, but only if you convert via an intermediate void* pointer.
Is that what you mean?

For example:

#include <stddef.h>
int main(void)
{
int i;
char c;

void *vp = &i;
char *cp = &c;
int *ip = &i;

vp = cp; /* ok */
cp = vp; /* ok */
vp = ip; /* ok */
ip = vp; /* ok */
cp = ip; /* constraint violation, incompatible types */
ip = cp; /* constraint violation, incompatible types */

vp = cp; ip = vp; /* legal but dangerous */
vp = ip; cp = vp; /* legal but dangerous */

cp = (char*)ip; /* legal but dangerous, conversion is explicit */
ip = (int*)cp; /* legal but dangerous, conversion is explicit */

return 0;
}

Note that some compilers might issue mere warnings rather than
fatal error messages for the constraint violations; the standard
permits this.
 
S

sandeep

Keith said:
vp = cp; /* ok */
cp = vp; /* ok */
vp = ip; /* ok */
ip = vp; /* ok */
cp = ip; /* constraint violation, incompatible types */ ip = cp; /*
constraint violation, incompatible types */

vp = cp; ip = vp; /* legal but dangerous */ vp = ip; cp = vp; /*
legal but dangerous */

cp = (char*)ip; /* legal but dangerous, conversion is explicit */ ip
= (int*)cp; /* legal but dangerous, conversion is explicit */

return 0;
}

Note that some compilers might issue mere warnings rather than fatal
error messages for the constraint violations; the standard permits this.

--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/
~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

It's interesting, some of the ones you label as OK are not OK on my
compiler but none of them generate any warning.

I tried out this code:
#include<stdio.h>
#include<stdlib.h>
main()
{
char* c;
void* v;
int* i=malloc(4);
*i=257; v=i; c=v;
printf("%hhd\n",*c);
c=malloc(1);
*c=7; v=c; i=v;
printf("%d\n",*i);
}

It produces
1
7

So the "int to char via void" fails but "char to int via void" succeeds.
 
K

Keith Thompson

Please don't quote signatures.
It's interesting, some of the ones you label as OK are not OK on my
compiler but none of them generate any warning.

By "ok", I merely meant that they don't violate any syntax error or
constraint. Not everything that's legal is safe.

Pointer conversions, even ones that are legal, can yield dangerous
results, sometimes immediately, sometimes later when you try to
access or dereference the pointer.
I tried out this code:
#include<stdio.h>
#include<stdlib.h>

Adding a space before the '<' will make these much more readable.

This should be "int main(void)". Haven't you been told this before?
{
char* c;
void* v;
int* i=malloc(4);

Where does the number 4 come from? What if int is bigger than 4 bytes?

Try this:
int *i = malloc(sizeof(int));
or, better yet, this:
int *i = malloc(sizeof *i)

And think about what to do if malloc() fails and returns a null pointer.
*i=257; v=i; c=v;
printf("%hhd\n",*c);

You're interpreting the first byte of the allocated int object as
if it were an object of type char. There's a special permission
that lets you do this with character types, but the results are at
best implementation-defined. It's not surprising that the result
is 1, but it could be 0 on a machine with different endianness,
or even 257 on an unusual system where CHAR_BIT > 8.

Don't try to interpret an object of one type as if it were an object
of another type (it's called "type-punning") unless you really know
what you're doing.
c=malloc(1);
*c=7; v=c; i=v;
printf("%d\n",*i);

Here you're interpreting a char object as if it were an int object.
Since int is (almost certainly) bigger than char, this means you're
accessing memory beyond the end of the object. (In this particular
case, given the way malloc() typically works, it probably won't
cause any visible bad results -- unfortunately.) It appears that
the extra bytes happened to be 0, but there's no guarantee of that.
}

It produces
1
7

So the "int to char via void" fails but "char to int via void" succeeds.

The first succeeded; it didn't access the entire int object
*because you told it not to*. The second "succeeded" only in the
sense that it didn't blow up; you accessed memory that you don't
own, but unfortunately the system didn't inform you of your error
(it's not required to do so, so avoiding this particular error is
entirely your responsibility).
 
E

Eric Sosman

Sandeep, you have already been asked not to quote signatures.
In fact, the post to which you made this reply contained just such
a request: "Please don't quote signatures," it said. And yet, you
keep on quoting signatures. Is your reading comprehension a bit
below par, or are you just trying to annoy people?
It's interesting, some of the ones you label as OK are not OK on my
compiler but none of them generate any warning.

It should come as no surprise that there exist fragments of C
code that are individually unobjectionable but collectively wrong.
For example, there's nothing wrong with taking an integer variable
x and dividing it by an integer variable y to get a quotient:

int quotient(int x, int y) {
return x / y;
}

All plain and above-board, right? Now try `quotient(42, 0)'. So,
don't equate "No complaints from the compiler" with "My code is
correct," or even with "My code's behavior is well-defined."
I tried out this code:
#include<stdio.h>
#include<stdlib.h>
main()
{
char* c;
void* v;
int* i=malloc(4);

You're assuming that sizeof(int) <= 4. Although this is true
on many machines it is not true universally, and besides it's silly
to make unnecessary assumptions. Write malloc(sizeof(int)), or
even better write malloc(sizeof *i).

You're also assuming that malloc() cannot fail, which just shows
that you are still wet behind the ears.
*i=257; v=i; c=v;

Okay, you now have c pointing to the first char of the same
object i points to. This will be one of the chars that make up the
representation of the integer value 257 (assuming 4 bytes are in
fact sufficient).
printf("%hhd\n",*c);

Now you print the value of that char. What you get is entirely
up to the implementation, because different implementations use
different schemes to store int values. In the commonest schemes,
two bytes of the representation of 257 will be 1 and the others (if
there are any) will be 0 -- but even that's not guaranteed. You
report that on your system the printed value was 1, so we can guess
(only guess) that your system uses one of the straightforward schemes,
but we cannot conclude as you do that it "doesn't work."
c=malloc(1);

Here, at least, you're requesting the right amount: sizeof(char)
is 1 by definition. But you're still assuming that malloc() doesn't
ever fail.
*c=7; v=c; i=v;

Okay, i now points to the spot where c points. But there's only
1 byte there (assuming malloc() succeeded), so if sizeof(int)>1 (which
the earlier printout proved is true for your system), you've got a
pointer-to-int aimed at memory-too-small-for-int.
printf("%d\n",*i);

... and here you try to read the entire int from the too-small
piece of memory. What happens is not just implementation-defined,
but undefined. *Any* output (or no output) is permitted, therefore
it is impossible to make deductions from whatever output you do or
don't see. It's possible to make guesses, but the guesses cannot
lead to a sure conclusion -- in particular, they cannot lead to the
conclusion "it succeeds."
}

It produces
1
7

So the "int to char via void" fails but "char to int via void" succeeds.

No; all you've shown is that you don't understand what you're
doing. I recommend more time with your C textbook or reference.
Fooling around just to see what happens is fine, to a point, but you
should at least be aware of when you're writing valid code and when
you're writing junk -- and you should know enough not to base any
deductions on the junk.

Of course, "Read the textbook" will only be helpful if your
reading comprehension improves above its present level. Please
don't quote signatures.
 
K

Kenny McCormack

Eric Sosman <[email protected]> apparently thought he was a
mother rebuking her child, when he wrote:
....
Sandeep, you have already been asked not to quote signatures.
In fact, the post to which you made this reply contained just such
a request: "Please don't quote signatures," it said. And yet, you
keep on quoting signatures. Is your reading comprehension a bit
below par, or are you just trying to annoy people?

One question for you: Do you do everything anyone asks you to do?
Are you that much of a slave to authority?

A major part of becoming a man is realizing who (and whose requests) can
and should be ignored.

--
(This discussion group is about C, ...)

Wrong. It is only OCCASIONALLY a discussion group
about C; mostly, like most "discussion" groups, it is
off-topic Rorsharch [sic] revelations of the childhood
traumas of the participants...
 
P

Peter Nilsson

[Subject: malloc() and implicit cast]

Other responses aside, there is no such thing as an implicit
cast. Casts are syntactical constructs, specifically, explicit
conversions. It is the _conversion_ that is implicit when
no cast is applied to the return result of malloc.
 
S

Seebs

malloc(size_t n) returns a void pointer and here in my program, I am
assigning malloc returned pointers to 2 different types and I am not
getting any warnings about <implicit cast>.
It has something to do with C90 ?

Yes, it's a standard feature of C. Why should you get any warnings? The
entire *point* of having malloc return (void *) is that you get no warnings
when converting it to other pointer types.

-s
 
S

Seebs

It's interesting, some of the ones you label as OK are not OK on my
compiler but none of them generate any warning.
Huh?

#include<stdio.h>
#include<stdlib.h>
main()
{
char* c;
void* v;
int* i=malloc(4);
*i=257; v=i; c=v;
printf("%hhd\n",*c);
c=malloc(1);
*c=7; v=c; i=v;
printf("%d\n",*i);
}
It produces
1
7
So the "int to char via void" fails but "char to int via void" succeeds.

This isn't even close to correct. No one EVER said, or suggested, or even
hinted, that a program like this would work.

All Keith said is that you can convert *POINTERS*. You are then running
off without ANY evidence whatsoever to the conclusion that somehow this will
magically convert the things pointed-to. It doesn't. If you access something
through a pointer of a different type, it is usually undefined behavior.

As a special exception, when you use unsigned char as the type to iterate
over something's bytes, you're guaranteed to see valid values which are in
some way a representation, but there's not really any general guarantee that
they'll make any sense.

I'm really pretty much sold on the theory that you're just trolling, though,
because you had to work pretty hard to come up with an example this bad.
No one at the level of expertise you're playing at would have known to
use 257, and "hhd" is a beautiful example of something which is funny to
people who remember joke proposals for "short short" as a counterpoint to
"long long", but is otherwise completely implausible and inappropriate.

Nice work, though. Very well constructed, looks almost like newbie code,
and the switcheroo in the layers of abstraction was done without any mention
or reference, making it easy to think you were just hopelessly confused.

-s
 
N

Nick Keighley

     Sandeep, you have already been asked not to quote signatures.
In fact, the post to which you made this reply contained just such
a request: "Please don't quote signatures," it said.  And yet, you
keep on quoting signatures.  Is your reading comprehension a bit
below par, or are you just trying to annoy people?

the "signature" is the text at the end following the marker "-- "


that's a signature or sig
 
S

Seebs

that's you, spinny, isn't it?

So far as I can tell, they're two different people obsessed with personal
status and how other people perceive them to the exclusion of any
personal development in terms of actual accomplishments or skills.

But I can see how you'd wonder. Kenny spells better, for the most part.

-s
 
N

Nick Keighley

So far as I can tell, they're two different people obsessed with personal
status and how other people perceive them to the exclusion of any
personal development in terms of actual accomplishments or skills.

But I can see how you'd wonder.  Kenny spells better, for the most part..

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

doesn't any of this apply to girls?
 
S

sandeep

Richard said:
%hhd? Short short int, perhaps?

?

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.
For one thing, the memory to which c points may not
be correctly aligned for an int.

I thought pointers returned by malloc would be aligned for anything.
The program fails because it abuses void *. Like any powerful tool, void
* can be abused. Don't be surprised if abusing it produces surprising
results.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

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

Seebs

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.

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.
I thought pointers returned by malloc would be aligned for anything.

If you allocate a single byte of memory, and try to use it for something
larger than one byte, not so much.
I still don't see why C lets you compile code correctly that will execute
incorrectly...

Then may I humbly suggest that you stop wasting your time and everyone
else's trying to use C, if you're unwilling to learn it, or listen to people
when they answer your questions the first five or six times?

-s
 

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,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top