Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > malloc() and implicit cast

Reply
Thread Tools

malloc() and implicit cast

 
 
sandeep
Guest
Posts: n/a
 
      06-03-2010
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 ?
 
Reply With Quote
 
 
 
 
mohangupta13
Guest
Posts: n/a
 
      06-03-2010
On Jun 3, 10:36*pm, sandeep <(E-Mail Removed)> wrote:
> 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?
> * 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 ?


 
Reply With Quote
 
 
 
 
Ben Pfaff
Guest
Posts: n/a
 
      06-03-2010
mohangupta13 <(E-Mail Removed)> writes:

> On Jun 3, 10:36*pm, sandeep <(E-Mail Removed)> wrote:
>> enum ARRSIZE { MAXSIZE = 100 };

....
>> * 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?


Members of enumerations just have type "int". You can use them
wherever you can use an int literal.
--
Ben Pfaff
http://benpfaff.org
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-03-2010
sandeep <(E-Mail Removed)> writes:
> 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>

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail 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"
 
Reply With Quote
 
sandeep
Guest
Posts: n/a
 
      06-03-2010
Keith Thompson writes:
> 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.

>> 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>
>
> --
> Keith Thompson (The_Other_Keith) (E-Mail 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?
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-03-2010
sandeep <(E-Mail Removed)> writes:
> Keith Thompson writes:
>> 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.


Correct, and yes, that's potentially dangerous.

>>> 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>
>>
>> --
>> Keith Thompson (The_Other_Keith) (E-Mail 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"


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.

--
Keith Thompson (The_Other_Keith) (E-Mail 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"
 
Reply With Quote
 
sandeep
Guest
Posts: n/a
 
      06-03-2010
Keith Thompson writes:
> 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 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.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-03-2010
sandeep <(E-Mail Removed)> writes:
> Keith Thompson writes:
>> 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.


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.

> main()


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).

--
Keith Thompson (The_Other_Keith) (E-Mail 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"
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      06-03-2010
On 6/3/2010 5:01 PM, sandeep wrote:
> Keith Thompson writes:
>> 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 Removed)<<a href="http://www.gh....ghoti.net</a>/
>> ~kst>


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.

--
Eric Sosman
(E-Mail Removed)lid
 
Reply With Quote
 
Kenny McCormack
Guest
Posts: n/a
 
      06-03-2010
In article <hu97p3$srj$(E-Mail Removed)-september.org>,
Eric Sosman <(E-Mail Removed)> 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...

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
implicit cast in templated function hweekuan@yahoo.com C++ 2 11-26-2008 04:59 PM
malloc() and implicit cast arnuld C Programming 7 04-16-2008 07:52 PM
Avoid implicit cast from enum to double Flo C++ 2 07-18-2006 01:27 PM
DynPtr: A pointer with implicit dynamic cast Calum Grant C++ 2 12-07-2005 04:54 AM
Implicit cast to object that implements overloaded operator pnsteiner@gmail.com C++ 7 10-12-2005 02:08 PM



Advertisments