Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does linking C with C++ avoid undefined behavior that is legal in C but not C++?

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++?

like image 743
Glenn Teitelbaum Avatar asked Aug 07 '15 16:08

Glenn Teitelbaum


People also ask

Why does C have so much undefined behavior?

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.

What type of behavior C is undefined?

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.


Video Answer


2 Answers

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".

like image 194
Raymond Chen Avatar answered Oct 09 '22 03:10

Raymond Chen


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.

like image 36
Lightness Races in Orbit Avatar answered Oct 09 '22 03:10

Lightness Races in Orbit