views:

404

answers:

8
#include<iostream>
using namespace std;

int main()
{
  int *p,*c;
  p=(int*)10;
  c=(int*)20;
  cout<<(int)p<<(int)c;
}

Somebody asked me "What is wrong with the above code?" and I couldn't figure it out. Someone please help me.

+9  A: 

The fact that int and pointer data types are not required to have the same number of bits, according to the C++ standard, is one thing - that means you could lose precision.

In addition, casting an int to an int pointer then back again is silly. Why not just leave it as an int?

I actually did try to compile this under gcc and it worked fine but that's probably more by accident than good design.

paxdiablo
I think you caught the intent of the question (which is clearly a trick question for an interview or somesuch), but I suppose the code will exhibit the intended behavior on any platform where both int and int* can represent the values 10 and 20.
Dan Olson
Dan is correct - the code, as written, will work on most modern platforms. But using pointers to store integers will generally cause crashes or other bugs if you dereference those pointers. You occasionally see people who really know what they're doing write code like this, but I consider it a dubious practice that should generally be avoided. As they say on Mythbusters, "Please don't try this at home!"
Bob Murphy
@Bob More frequently, you see people who really DON'T know what they are doing writing code like this.
anon
It's not just "silly" to cast int to int pointer and back. It is implementation-defined, and most likely, not every integer converts to a valid int pointer, so on some platforms, the code might crash even if the pointers are never dereferenced.
jalf
@jalf, implementation-defined isn't a bad thing provided you know it's limitations (and you're not concerned about massive portability). As I stated, gcc under Ubuntu worked fine for this although you really need to check the doco for your compiler to be sure (I didn't). My point was, even if the implementation allowed it, it's still a silly thing to do.
paxdiablo
True. I just wanted to point out that it may actually fail on some systems, which would often be considered more than "silly" ;)
jalf
A: 

You're assigning values (10 and 20) to the pointers which obviously is a potential problem if you try to read the data at those addresses. Casting the pointer to an interger is also really ugly. And your main function does not have a return statement. That is just a few things.

Cellfish
main() doesn't need a return statement. The standards compliant compiler inserts it. http://www2.research.att.com/~bs/bs_faq2.html , refere to the question "Can I write "void main()"?.
Jagannath
You can write "void main()" which would be better IMHO. I know the compiler adds the return statement but it is hardly good practice to write code with a bunch of warnings when compiling and basically everything that is wrong with the code would generate compiler warnings so my point is; turn on all warnings and you'll see get helpfrom the compiler to know "what is wrong with the code".
Cellfish
A: 

Assuming I'm right about what this is supposed to be, it should look like this:

int main()
{
  int *p, *c;
  // Something that creates whatever p and c point to goes here, a trivial example would be.
  int pValue, cValue;
  p = &pValue;
  c = &cValue;
  // The & operator retrieves the memory address of pValue and cValue. 

  *p = 10;
  *c = 20;
  cout << *p << *c;
}

In order to assign or retrieve a value to a variable referenced by a pointer, you need to dereference it.

What your code is doing is casting 10 into pointer to int (which is the memory address where the actual int resides).

Adam Luchjenbroers
This will segfault on most implementations.
Prasoon Saurav
Dereferencing a "wild pointer" is Undefined Behavior.
Prasoon Saurav
@Adam, I'll give you the benefit of the doubt and assume you meant "this is what your *problem* code should look like" rather than "this code is the solution to your problem". Since p and c are uninitialized, they could be set to *anything* which is undefined behaviour.
paxdiablo
Sorry, forgot to put that bit in. Fixed.
Adam Luchjenbroers
I have upvoted you, you have corrected your code. :-)
Prasoon Saurav
A: 

addresses p and c may be larger than int.

fupsduck
or smaller than int
swegi
@fupsduck: Addresses p and c will be of size as that of a int. All pointers are 32 bit, same as int size.
goldenmean
@goldenmean, 64 bits pointers and 32 bits ints aren't a rarety these days.
AProgrammer
+1  A: 

The result is Implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

I could not find this in C++ Standard but I dont think there would be much difference between both the languages(C and C++) as far as OP's question in concerned.

From (C99-6.3.2.3)

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type. As far as portable code is concerned, that last possibility is the most significant one. Storing a trap representation in i will cause your program's behavior to be undefined. .

Prasoon Saurav
If you're going to quote the standard, @Prasoon, at least quote the *right* one :-) In addition, there's a *big* difference between implementation-defined and undefined.
paxdiablo
If I have made a mistake please correct me then.
Prasoon Saurav
The question was a C++ one. I was merely pointing out you should find the relevant section in the C++ standard rather than C99. I have no idea off the top of my head whether it's the same in both standards.
paxdiablo
OP's code shows implementation defined behavior and if there is a trap representation the code invokes UB. Where am I wrong? Yeah, you are right I should have quotes C++ Standard rather. xD
Prasoon Saurav
Why two down votes x-( ?.....
Prasoon Saurav
Because you're quoting from the wrong standard and don't seem to acknowledge that it's wrong. C and C++ are different languages, and especially pointer-integer conversions were changed in the C99 standard, so my initial guess would be that the C standard would not help give a correct answer for C++, and you don't provide any real reason why it should.
jk
@jk: I dont think there would be huge different C and C++ pointer-integer conversion, please enlighten me.
Prasoon Saurav
A: 

there is more or less everything wrong with it:

int *p,*c;
p=(int*)10;
c=(int*)20;
  • afterwards p is pointing to memory address 10
  • afterwards c is pointing to memory address 20

This doesn't look very intentional.

And I suppose that the whole program will simply crash.

No, it won't crash, as long as you don't try to use those pointers to *reference* memory addresses 10 and 20.
Bob Murphy
All depending on the level of memory protection applied, though...
e8johan
@Bob: It might crash. It is implementation-defined. The CPU could detect that these are invalid pointers, and trap as soon as the pointers are created.
jalf
+8  A: 

Some wanted a quote from the C++ standard (I'd have put this in the comments of that answer if the format of comments wasn't so restricted), here are two from the 1999 one:

5.2.10/3

The mapping performed by reinterpret_cast is implementation defined.

5.2.10/5

A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if ant such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.

And I see nothing mandating that such implementation-defined mapping must give a valid representation for all input. Otherwise said, an implementation on an architecture with address registers can very well trap when executing

p = (int*)10;

if the mapping does not give a representation valid at that time (yes, what is a valid representation for a pointer may depend of time. For instance delete may make invalid the representation of the deleted pointer).

AProgrammer
Upvoted for the second quote. C-style casts and reinterpret_cast have different behavior so I'm not certain the first quote applies.
Dan Olson
Dan, the whole 5.2.10 section is about reinterpret_cast, so both quotes are about reinterpret_cast. But in C++, the syntax of C cast is defined in terms of the other casts, and in this case, it is the reinterpret_cast definition which applies.
AProgrammer
@AProgrammer: Thanks, I could not find it in the C++ Standard :)
Prasoon Saurav
In practice, the pointers most likely won't be valid (assuming int requires 4-byte alignment, at least the 10 one won't be properly aligned) And of course, both are likely to point to an unmapped page of memory. Plenty of opportunities for the CPU to trap.
jalf
@jalf, there is plenty of opportunities to trap when dereferencing the pointer on common architectures; I was especially pointing out that the standard allows to trap when loading the pointer without dereferencing it (if you use segment, you can get that such traping on a x86)
AProgrammer
@AProgrammer: Yes, that's what I meant too. Sorry if it seemed like I disagreed. I just wanted to provide other examples of why a CPU might trap as soon as the pointer was loaded, even if it's never dereferenced. +1 from me
jalf
A: 

The problem on some platforms you need

p = (int*) (long) 10;

See GLIB documentation on type conversion macros.

And for the people who might not find a use for this type of expressions, it is possible to return data inside pointer value returning functions. You can find real-world examples, where this case it is better to use this idiom, instead of allocating a new integer on the heap, and return it back - poor performance, memory fragmentation, just ugly.

ccer