Can code that is valid in both C and C++ produce different behavior when compiled in each language?
The following, valid in C and C++, is going to (most likely) result in different values in i
in C and C++:
int i = sizeof('a');
See Size of character ('a') in C/C++ for an explanation of the difference.
Another one from this article:
#include <stdio.h>
int sz = 80;
int main(void)
{
struct sz { char c; };
int val = sizeof(sz); // sizeof(int) in C,
// sizeof(struct sz) in C++
printf("%d\n", val);
return 0;
}
Can code that is valid in both C and C++ produce different behavior when compiled in each language?
The following, valid in C and C++, is going to (most likely) result in different values in i
in C and C++:
int i = sizeof('a');
See Size of character ('a') in C/C++ for an explanation of the difference.
Another one from this article:
#include <stdio.h>
int sz = 80;
int main(void)
{
struct sz { char c; };
int val = sizeof(sz); // sizeof(int) in C,
// sizeof(struct sz) in C++
printf("%d\n", val);
return 0;
}
Do external variables always need to be volatile when compiled with gcc?
The calculation &ex_var+16
is not defined by the C standard (because it only defines pointer arithmetic within an object, including to the address just beyond its end) and the assignment *pos++ = 1
is not defined by the C standard (because, for the purposes of the standard, pos
does not point to an object). When there is behavior not defined by the C standard on a code path, the standard does not define any behavior on the code path.
You can make the behavior defined, to the extent the compiler can see, by declaring ex_var
as an array of unknown size, so that the address calculation and the assignments would be defined if this translation unit were linked with another that defined ex_var
to be an array of sufficient size:
extern unsigned int ex_var[];
int main ()
{
ex_var[0] = 56326;
unsigned int *pos = ex_var+16;
for (int i = 0; i < 6; i++ )
{
*pos++ = 1;
}
*(volatile unsigned int*)(0x00100000) = ex_var[0];
}
(Note that *(volatile unsigned int*)(0x00100000) =
remains not defined by the C standard, but GCC is intended for some use in bare-metal environments and appears to work with this. Additional compilation switches might be necessary to ensure it is defined for GCC’s purposes.)
This yields assembly that sets ex_var[0]
and uses it in the assignment to 0x00100000
:
main:
mov DWORD PTR ex_var[rip], 56326
…
mov eax, DWORD PTR ex_var[rip]
mov DWORD PTR ds:1048576, eax
mov eax, 0
ret
Application behaves differently on different machines
The textbook is wrong if it that’s exactly what it says: %d
is a conversion specifier for an int
, but move
is a long int
. The correct call would be:
scanf("%ld", &move)
, with similar corrections to several printf
calls.
It can work by coincidence, especially when long
and int
happen to be the same size (as they are in 64-bit Windows, but not in 64-bit Linux). With the mismatches, however, no particular behaviour is defined for the entire program: the compiler is allowed by the language standard to assume that the kind of illegal actions they represent never happen, and has no obligation whatever as to what a program that performs such an action may do.
Related Topics
C++ Catch Blocks - Catch Exception by Value or Reference
Standard Library Sort and User Defined Types
What Are the Pointer-To-Member Operators -≫* and .* in C++
High Resolution Timer With C++ and Linux
Should I Use Std::Function or a Function Pointer in C++
Split a String into Words by Multiple Delimiters
Comparing Iterators from Different Containers
Is Sizeof in C++ Evaluated At Compilation Time or Run Time
Splitting a C++ Std::String Using Tokens, E.G. ";"
When Passing an Array to a Function in C++, Why Won't Sizeof() Work the Same as in the Main Function
How to Get the Md5 Hash of a File in C++
Initializing a Two Dimensional Std::Vector
Converting a Pointer into an Integer
Convert a Vector≪Int≫ to a String
C++ How to Determine Whether a Pointer Points to a Valid Object