3

I wrote a simple C program and I was expecting that it will fail in compilation but unfortunately it compiles and runs fine in C, but fails in compilation in C++. Consider below program:

#include <stdio.h>
int main()
{
    char *c=333;
    int *i=333;
    long *l=333;
    float *f=333;
    double *d=333;
    printf("c = %u, c+1 = %u",c,c+1);
    return 0;
}

Visit this link: http://ideone.com/vnKZnx

I think that this program definitely can't compile in C++ due to C++'s strong type checking. Why this program compiles in C? It is the fact that compiler shows warnings also. I am using Orwell Dev C++ IDE(gcc 4.8.1 compiler). I also tried same program on other compiler (Borland Turbo C++ 4.5) , saved it by extension .c and on this compiler it failed to compile.

Destructor
  • 14,123
  • 11
  • 61
  • 126
  • 1
    @haccks Which part of the program invokes undefined behavior? Assigning a random value to a pointer variable is perfectly valid as long as you don't dereference it. – 5gon12eder Sep 08 '14 at 13:27
  • 1
    @5gon12eder; This part: `printf("c = %u, c+1 = %u",c,c+1);`. Do you need explanation ? – haccks Sep 08 '14 at 13:28
  • @meet Your compiler should really present you a warning, though. GCC does so even without any additional warning flags enabled. If you really mean it, you can suppress the warning with an explicit cast. (This will also work in C++.) – 5gon12eder Sep 08 '14 at 13:29
  • 2
    @haccks That's true, the `%u` should be changed to `%p`. However this has nothing to do with meet's question and does not explain why the program compiles. – 5gon12eder Sep 08 '14 at 13:33
  • @haccks, it is not UB it is a constraint violation. – Jens Gustedt Sep 08 '14 at 14:14
  • @JensGustedt; C11: 7.21.6: `If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.` – haccks Sep 08 '14 at 14:17
  • @haccks, UB is a runtime error, a constraint violation is a compile time error. Here there isn't even a valid executable that is generated. And in particular suggesting that "it compiles fine" is due to the fact that there is UB is completely misleading. It doesn't compile fine in the first place, and that's what the OP overlooked. – Jens Gustedt Sep 08 '14 at 14:29
  • 1
    @JensGustedt; I admit that my comment was misleading and I deleted that. But I think there is UB, although executable is not valid. – haccks Sep 08 '14 at 14:42
  • 1
    @davmac Undefined behavior includes "terminating a translation or execution". – T.C. Sep 09 '14 at 02:10

3 Answers3

7

This code is neither legal C nor legal C++.

N1570 §6.7.9/p11:

The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.

§6.5.16.1/p1 provides that for simple assignment:

One of the following shall hold:

  • the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
  • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
  • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
  • the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

None of which matches a pointer on the left and 333 on the right. §6.5.16.1/p1 is a constraint, and conforming implementations are required to produce a diagnostic upon a constraint violation (§5.1.1.3/p1):

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined.

It happens that GCC decides to produce a warning instead of an error in C mode and continue to compile it, but it doesn't have to.

T.C.
  • 133,968
  • 17
  • 288
  • 421
5

C can convert numbers to pointers. char* c = 123 will set c to point to the 123rd byte in memory.

While this is nearly useless and almost certainly an error in desktop programming, in embedded systems it is necessary to interface with the hardware, which may look for values in certain, hardcoded memory addresses.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
  • 3
    While this is part of an answer, it doesn't say why and how this code is in fact a constraint violation, so *every* C compiler must at least give a diagnostic, and indeed the OP admits somewhere that it didn't compile fine, but gives warnings. – Jens Gustedt Sep 08 '14 at 14:11
-2

Ethnically there is nothing wrong with your code. You are initializing the pointers with the integer constant values 333. and then printing the address. The warning it shows is probably because the integer value is type casted to address type.

the problem will start when you would try to dereference the pointers. It will give segmentation fault.

Haris
  • 12,120
  • 6
  • 43
  • 70