标签云

微信群

扫码加入我们

WeChat QR Code

C and C++ have many differences, and not all valid C code is valid C++ code.(By "valid" I mean standard code with defined behavior, i.e. not implementation-specific/undefined/etc.)Is there any scenario in which a piece of code valid in both C and C++ would produce different behavior when compiled with a standard compiler in each language?To make it a reasonable/useful comparison (I'm trying to learn something practically useful, not to try to find obvious loopholes in the question), let's assume:Nothing preprocessor-related (which means no hacks with #ifdef __cplusplus, pragmas, etc.)Anything implementation-defined is the same in both languages (e.g. numeric limits, etc.)We're comparing reasonably recent versions of each standard (e.g. say, C++98 and C90 or later)If the versions matter, then please mention which versions of each produce different behavior.


By the way, it can be useful to program in a dialect which is C and C++ at the same time. I've done this in the past and one one current project: the TXR language. Interestingly, the developers of the Lua language did the same thing, and they call this dialect "Clean C".You get the benefit of better compile time checking and possibly additional useful diagnostics from C++ compilers, yet retain the C portability.

2019年06月26日40分32秒

I merged the older question into this question since this has more views and upvoted answers.This is still an example of a non-constructive question, but it's quite borderline since yes, it does teach SO users something.I'm closing it as not constructive only to reflect the state of the question before the merge.Feel free to disagree and re-open.

2019年06月25日40分32秒

Voting to reopen as I think it can be objectively answered with a "yes" followed by an example (as proved below). I think it is constructive in that people can learn relevant behaviour from it.

2019年06月25日40分32秒

AndersAbel The pure number of answers, all of which are correct, demonstrates unambiguously that it remains a make-a-list question. There was no way you could have asked this question without getting a list.

2019年06月25日40分32秒

dmckee For what it's worth, I agree with you.However, the C++ tag people are... Shall we say... feisty.

2019年06月25日40分32秒

Definitely wasn't expecting this one! I was hoping for something a little more dramatic but this is still useful, thanks. :) +1

2019年06月25日40分32秒

+1 the second example is a good one for the fact that C++ doesn't require struct before struct names.

2019年06月26日40分32秒

Andrey I thought the same a while ago and tested it and it worked on GCC 4.7.1 without the std, contrary to my expectation. Is that a bug in GCC?

2019年06月26日40分32秒

SethCarnegie: A non-conforming program need not fail to work, but it is not guaranteed to work either.

2019年06月25日40分32秒

struct sz { int i[2];}; would mean that C and C++ have to produce different values.(Whereas a DSP with sizeof(int) == 1, could produce the same value).

2019年06月26日40分32秒

Strictly speaking under C this will not compile, becausethe declaration of "int f()" is after the definition of "int main()" :)

2019年06月25日40分32秒

Sogartar, really? codepad.org/STSQlUhh C99 compilers will give you a warning, but they'll still let you compile it.

2019年06月25日40分32秒

Sogartar in C functions are allowed to be implicitly declared.

2019年06月25日40分32秒

AlexB Not in C99 and C11.

2019年06月26日40分32秒

jrajav Those are not C99 compilers, then. A C99 compiler detects undeclared identifiers as a syntax error. A compiler that doesn't do that is either a C89 compiler, or a pre-standard or another kind of non-conformant compiler.

2019年06月25日40分32秒

WHOA this is mind-blowing!! Of all possible things I would never have thought comments could be used to change behavior haha. +1

2019年06月25日40分32秒

even without the 2,it would read as 10 / + 3 which is valid (unary +).

2019年06月26日40分32秒

Now for fun, modify it so that C and C++ both calculate different arithmetic expressions the evaluate to the same result.

2019年06月25日40分32秒

RyanThompson Trivial. s/2/1/

2019年06月26日40分32秒

Mehrdad Am I wrong or comments are preprocessor-related? They should thus be excluded as a possible answer from your question! ;-)

2019年06月26日40分32秒

C90 has auto?

2019年06月25日40分32秒

Yes: tigcc.ticalc.org/doc/keywords.html#auto

2019年06月25日40分32秒

SethCarnegie: Yeah, it's a storage class; it's what happens by default when you omit it, so no one used it, and they changed its meaning. I think it's int by default. This is clever! +1

2019年06月25日40分32秒

KeithThompson Ah, I guess you mean the inferred int. Still, in the real world, where there istons of legacy code and the market leader still hasn't implemented C99 and has no intent to do so, talk of "an obsolete version of C" is absurd.

2019年06月26日40分32秒

"Every variable MUST have an explicit storage class. Yours truly, upper management."

2019年06月26日40分32秒

Interesting. Does anyone know the rationale behind this change?

2019年06月25日40分32秒

because "true" is a key word/valid value, so it is evaluated to true like any "true value" (so like any positive integer). You can still do #define true false toprint "false" in C++ too ;)

2019年06月25日40分32秒

#define true false ಠ_ಠ

2019年06月25日40分32秒

DarioOO won't such redefinition result in UB?

2019年06月25日40分32秒

DarioOO: Yes, you are wrong. Re-definition of keywords is not allowed, punishment left to fate (UB). The preprocessor being a separate phase of compilation not withstanding.

2019年06月25日40分32秒

The first one is also implementation-defined like Alexey's. But +1.

2019年06月25日40分32秒

Seth, All material above is taken directly from Annex C.1 of the C++11 standard.

2019年06月25日40分32秒

Yes but it is still implementation-defined. sizeof(char*) could be 100 in which case the first example would produce the same observable behaviour in C and C++ (i.e. though the method of obtaining s would be different, s would end up being 100). The OP mentioned that this type of implementation-defined behaviour was fine as he was just wanting to avoid language-lawyer answers, so the first one is fine by his exception. But the second one is good in any case.

2019年06月25日40分32秒

There is an easy fix -- just change the example to: char arr[sizeof(char*)+1]; int s = sizeof(0, arr);

2019年06月26日40分32秒

To avoid implementation-defined differences, you could also use void *arr[100].In this case an element is the same size as a pointer to the same element, so as long as there are 2 or more elements, the array must be larger than the address of its first element.

2019年06月25日40分32秒

had to debug code of someone else with that issue. Oh How I loved that. Anyway your program is printing 0 in C++ too. C++ have to use the header "cmath" see comparison first one returnin 0 ideone.com/0tQB2G 2nd one returning 1 ideone.com/SLeANo

2019年06月25日40分32秒

Glad/sorry to hear that I'm not the only who find this difference via debugging. Just tested in VS2013, an empty with only file with this content will output 1 if extension is .cpp, and 0 if extension is .c. Looks like <math.h> is included indirectly in VS.

2019年06月25日40分32秒

And looks like in VS C++, <math.h> includes C++ stuff into global namespace, where as for GCC it is not. Unsure which is standard behavior however.

2019年06月25日40分32秒

no it is not, but lot of users would not be able to compile code written for visual studio if they don't add missing includes;) and even worse, there's the chance users won't get compile errors but strange numerical behaviour due to that non standard behaviour (which could be disabled from options but is enabled by default)

2019年06月25日40分32秒

A secondary issue is that although the C++ standard does appear to say that including <math.h> also includes the additional overloads;in practice it turns out that all the major compilers don't include those overloads unless the form <cmath> is used.

2019年06月25日40分32秒

One ! should be enough for a bool.

2019年06月25日40分32秒

!! is the int to boolean conversion operator :)

2019年06月25日40分32秒

sizeof(0) is 4 in both C and C++ because 0 is an integer rvalue. sizeof(!0) is 4 in C and 1 in C++. Logical NOT operates on operands of type bool. If the int value is 0 it is implicitly converted to false (a bool rvalue), then it is flipped, resulting in true. Both true and false are bool rvalues in C++ and the sizeof(bool) is 1. However in C !0 evaluates to 1, which is an rvalue of type int. C programming language has no bool data type by default.

2019年06月25日40分32秒

Yes, I was actually familiar with this trick, being that 'c' is an int in C, and a char in C++, but it's still good to have it listed here.

2019年06月25日40分32秒

That would make an interesting interview question - especially for people that put c/c++ expert on their CVs

2019年06月26日40分32秒

Kind of underhanded though. The whole purpose of sizeof is so you don't need to know exactly how large a type is.

2019年06月25日40分32秒

In C the value is implementation defined and 1 is a possibility.(In C++ it has to print 1 as stated.)

2019年06月25日40分32秒

Actually it has undefined behavior in both cases. %d is not the right format specifier for size_t.

2019年06月26日40分32秒

So, that's only in C89 compilers, not modern ones...

2019年06月25日40分32秒

so you get padding differences ?

2019年06月26日40分32秒

ah sorry i got it, there is another x at the top. i thought you said "the array a".

2019年06月26日40分32秒

I really don't think so. Probably you have missed the point. It's not about definition of struct st which is merely used to make the code valid c++. The point is that it highlights different behavior of inline functions in c vs c++. Same applies to extern. None of these is discussed in any of the solutions.

2019年06月25日40分32秒

What is the different behavior of inline functions and extern that is demonstrated here?

2019年06月26日40分32秒

It is written pretty clearly. "Inline functions in c default to external scope where as those in c++ are not (code shows that). Also C++ implicitly treats any const global as file scope unless it is explicitly declared extern, unlike C in which extern is the default. A similar example can be created for that". I am puzzled - Is it not understandable?

2019年06月25日40分32秒

fayyazkl The behaviour shown is only because of the difference of lookup (struct fun vs fn) and has nothing to do whether the function is inline. The result is identical if you remove inline qualifier.

2019年06月26日40分32秒

In ISO C this program is ill formed: inline was not added until C99, but in C99 fun() may not be called without a prototype in scope.So I assume this answer only applies to GNU C.

2019年06月25日40分32秒

Your second example using exit, doesn't compile on gcc or g++, unfortunately. It's a good idea, though.

2019年06月26日40分32秒

exit(code) is a valid declaration of a variable code of type exit, apparently. (See "most vexing parse", which is a different but similar issue).

2019年06月26日40分32秒

This one is interesting!(I think you mean 32*sizeof(double) rather than 32 though :))

2019年06月26日40分32秒

Oh yes, ofcourse. Fixing it now. :)

2019年06月26日40分32秒

note that you're getting UB by printing size_t with %d

2019年06月25日40分32秒

You mean the linkage specification?

2019年06月25日40分32秒

name mangling. C++ names have prefixes and suffixes while C not

2019年06月25日40分32秒

Name mangling is not a part of the C++ specification. Is it prohibited in C?

2019年06月25日40分32秒

This is undefined behaviour (multiple definition of foo). There are not separate "global namespaces".

2019年06月26日40分32秒

There's no "valid in C" here.

2019年06月26日40分32秒

No, the difference is that C does not have empty structures, except as a compiler extension, i.e. this code does not match "is valid in both C and C++"

2019年06月25日40分32秒