25

Recently, I found out there are some cases that will absolutely violate the ODR of C++ but will be compiled OK in C compiler.

For example, this wierd scenario (with me):

Source 1

int var_global=-3;

Source 2

#include <stdio.h>
#include <conio.h>

unsigned int var_global;

int main() {    

 printf("%d \n",var_global);
 getch();
 return 0;

}

I have the printed result is -3 (even though in Source 2 var_global is unsigned) and there is no error about the redefined of var_global.

I knew that C have different rules with C++ but I don't think it's so different like that.

I have google and read a lot of results but there is no official result like this of C++.

So question is:

Does C have One Definition Rule like C++ ?

and:

What is it called officially?

I need it to compare with the rule of C++ so that I can understand both languages deeper.

p/s: I used Visual Studio 2010 for compiling the code above.

Van Tr
  • 5,889
  • 2
  • 20
  • 44
  • 2
    "will absolutely violate the ODR of C++ but will be compiled OK in C compiler". Have you tried to compile it with a C++ compiler? Any actual error message? – n. m. could be an AI Jan 25 '16 at 06:42
  • 8
    ***Please do not change the question after the question has been answered.*** It makes the answerer(s) look like fools. :) you can always [edit] the question and use comments to ask for more clarity. – Sourav Ghosh Jan 25 '16 at 06:53
  • sorry, I have mentioned what I edited but don't know why it does not display. Let me re-edit it. – Van Tr Jan 25 '16 at 06:55
  • Well... do you link the 2 files together? How? From what we can see in your question, there is nothing in source 1 being even used by the project. There's no difference between C and C++ here. So it would seem you are simply using 2 entirely different linkers and goofing up the linking in the C case? – Lundin Jan 25 '16 at 07:16
  • @Lundin of course I build both file in same project. – Van Tr Jan 25 '16 at 07:18
  • But how do you use anything from source 1 in your code? If you don't use anything from it, the linker is free to ignore that file and then you won't get any linker errors. – Lundin Jan 25 '16 at 07:21
  • depends on your compiler. what specific version, target, command line options, operating system, version, etc. results will vary as you try different compilers. – old_timer Jan 29 '16 at 03:45

2 Answers2

19

I think what you're looking for is chapter §6.2.7 from the C11 standard, Compatible type and composite type, (emphasis mine)

All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.

and related to compatible type,

Two types have compatible type if their types are the same.

In your case, int and unsigned int are not compatible types. Hence undefined behavior.

Just to add a bit of clarity, in your source 2, unsigned int var_global; is a declaration, and it does not match the other declatation (and definition), so, this is UB.

That said, a statement like

 printf("%d \n",var_global);

will always consider the argument to %d to be of type int. In case the type and the format specifier does not match, you'll again invoke undefined behavior.


EDIT:

After the edit, the answer is, use -fno-common to get the desired error. (missing extern is what you're bothered with, I believe).

Quoting from online GCC manual,

-fno-common

In C code, controls the placement of uninitialized global variables. Unix C compilers have traditionally permitted multiple definitions of such variables in different compilation units by placing the variables in a common block. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references. The -fno-common option specifies that the compiler should place uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without extern) in two different compilations, you get a multiple-definition error when you link them. In this case, you must compile with -fcommon instead. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable declarations this way.


I don't know of any mention of the wordings "one definition rule" in the C standard, but along the line, you can look into annex §J.5.11, Multiple external definitions,

There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I have edited the source for avoid confusing, please check the question again. This case lead to redefine error in C++ compiler but not in C compiler. That why I asked for the ODR of C. – Van Tr Jan 25 '16 at 06:54
  • 1
    @TrieuTheVan you did not clarify the question, you __changed__ the question. – Sourav Ghosh Jan 25 '16 at 06:54
  • I have two questions which are in bold and they were not changed anything :). May be the code make confuse (and I have fixed them) but the two question are very clearly. – Van Tr Jan 25 '16 at 07:04
  • @TrieuTheVan The question is not only the **bold** lines, it comes along with the code, too. and just to make sure, you do understand the impact of changing an `int` to `unsigned int` in a code like this, right? – Sourav Ghosh Jan 25 '16 at 07:06
  • Yes, I do know the impact of changing the unsigned int to int. What I want to ask is about the definition rules of C (and the rules is not just about variable but function, not just about global but static objects). That why I ask for something like ODR of C++ to compare (like I said in the question). – Van Tr Jan 25 '16 at 07:14
  • @TrieuTheVan well, OK, then. Does this answers suit your need? – Sourav Ghosh Jan 25 '16 at 07:16
  • yes, I've voted for your answer but I still expect an answer with an official material of language not from the specific compiler (like GCC in your case). – Van Tr Jan 25 '16 at 07:21
  • 1
    @TrieuTheVan Well, I have added the standard quotes as per my knowledge. Will look forward to get more insight into it in case some other answer clarifies more. :) – Sourav Ghosh Jan 25 '16 at 07:33
2

What you're seeing has nothing to do with a one-definition rule. It has to do with the fact that %d expects a signed value and therefore will almost certainly just be treating it as a signed value in your implementation.

However, this is not something you should rely on. As per the C standard 7.19.6.1 The fprintf function /9 (I'm referencing C99 but C11 is pretty much the same in term of the aspects shown here):

If any argument is not the correct type for the corresponding conversion specification, the behaviour is undefined.

Since you're using undefined behaviour, the implementation is free to do whatever it wants. In addition, the standard also specifically states that it's undefined behaviour if (from Annex J):

two declarations of the same object or function specify types that are not compatible.

In your case, those two declarations do specify the same object since they both have external linkage.

Now you might think that signed and unsigned integers would be compatible but you would be wrong: 6.2.7 Compatible and composite type, and 6.2.5 Types makes it clear that signed and unsigned variants are not compatible:

Two types have compatible type if their types are the same.

For each of the signed integer types, there is a corresponding (but different) unsigned integer type (designated with the keyword unsigned) that uses the same amount of storage (including sign information) and has the same alignment requirements.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • yes, I know about %d point but in this case what I focus on is the variable is redefined and it's ok for C compiler. – Van Tr Jan 25 '16 at 06:37
  • @paxdiablo sir, I've added back the tags. In case you disagree with the tagging, please let me know. Thanks. :) – Sourav Ghosh Jan 27 '16 at 15:13