If you have a C file, compiled with a C compiler and have defined behavior for C but not C++, can you link it with a C++ file and not have undefined behavior?
in blah.c (the file compiled as C)
struct x {
int blah;
char buf[];
};
extern char * get_buf(struct x * base);
extern struct x * make_struct(int blah, int size);
blah_if.h
extern "C"
{
struct x;
char * get_buf(struct x * base);
struct x * make_struct(int blah, int size);
}
some_random.cpp (Compiled with a C++ compiler)
#include "blah_if.h"
...
x * data=make_struct(7, 12);
std::strcpy(get_buf(data), "hello");
Is using the defined behavior in C's flexible array member in a file compiled with a C compiler, defined behavior when used by a file compiled as C++ and linked with the object from the C compiler?
Note that because a C compiler is used and struct x
is opaque, this is different than:
Does extern C with C++ avoid undefined behavior that is legal in C but not C++?
It exists because of the syntax rules of C where a variable can be declared without init value. Some compilers assign 0 to such variables and some just assign a mem pointer to the variable and leave just like that. if program does not initialize these variables it leads to undefined behavior.
According to the C standards, signed integer overflow is undefined behaviour too. A few compilers may trap the overflow condition when compiled with some trap handling options, while a few compilers simply ignore the overflow conditions (assuming that the overflow will never happen) and generate the code accordingly.
The behavior is implementation-defined.
[dcl.link] Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent.
It continues:
Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved.
That sentence in the standard really should be an annotation, since it doesn't specify what counts as "similar enough".
As Raymond has already said, this is implementation-defined at the formal, language level.
But it's important to remember what your compiled code is. It's not C++ code any more, nor is it C code. The rules about the behaviour of code in those languages apply to code written in those languages. They are taken into consideration during the parsing and translation process. But, once your code has been translated into assembly, or machine code, or whatever else you translated it to, those rules no longer apply.
So it's effectively meaningless to ask whether compiled C code has UB. If you had a well-defined C program, and compiled it, that's that. You're out of the realm of being able to discuss whether the compiled program is well-defined or not. It's a meaningless distinction, unless you have somehow managed to generate a program that is dictated to have UB by the specification for your assembly or machine language dialect.
The upshot of all this is that the premise of your question is unsound. You can't "avoid undefined behaviour" when linking to the compiled result of a C program, because the very notion of "undefined behaviour" does not exist there. But, as long as the original source code was well-defined when you translated it, you will be fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With