C vs C++

Not about OpenMW? Just about Morrowind in general? Have some random babble? Kindly direct it here.
User avatar
psi29a
Posts: 5361
Joined: 29 Sep 2011, 10:13
Location: Belgium
Gitlab profile: https://gitlab.com/psi29a/
Contact:

Re: C vs C++

Post by psi29a »

Lgro, try again but with -m32 ;)
bidik
Posts: 24
Joined: 28 Apr 2017, 12:06

Re: C vs C++

Post by bidik »

Lgro?
User avatar
Capostrophic
Posts: 794
Joined: 22 Feb 2016, 20:32

Re: C vs C++

Post by Capostrophic »

bidik wrote:Lgro?
Short for Lucasz Gromanowski.
User avatar
lgromanowski
Site Admin
Posts: 1193
Joined: 05 Aug 2011, 22:21
Location: Wroclaw, Poland
Contact:

Re: C vs C++

Post by lgromanowski »

Capostrophic wrote:
bidik wrote:Lgro?
Short for Lucasz Gromanowski.
Yeah, exactly, it's just a short :-)
User avatar
psi29a
Posts: 5361
Joined: 29 Sep 2011, 10:13
Location: Belgium
Gitlab profile: https://gitlab.com/psi29a/
Contact:

Re: C vs C++

Post by psi29a »

Applying Rust to Machine Learning (ML).

https://www.youtube.com/watch?v=lY10kTcM8ek

They use Python (iPython) as a notepad for one-off data science but once you try to get it into production is where Rust shines.
User avatar
raevol
Posts: 3093
Joined: 07 Aug 2011, 01:12
Location: Caldera

Re: C vs C++

Post by raevol »

Alright, I got permission from my professor to post my code. Here we go kiddos...

So first, here's the assignment:

*snip* - removed, contact me if you want to see this
Attachments
hex_grid.png
Mishtal
Posts: 28
Joined: 13 Dec 2016, 06:45

Re: C vs C++

Post by Mishtal »

I'm a professional c++ programmer with 10-ish years of experience in industry, and both a bachelors degree in software engineering, as well as a masters degree in the same. I happen to specialize in the low level bits of application frameworks, like c++ template metaprogramming for libraries, and hand-tuning library functions to get that little bit of extra performance, or writing new functionality when given very specific performance constraints (e.g. don't allocate data structures larger than X, max size on function stack, fully async apis, so on).

At the moment, I maintain my employers c++ STL implementation (no, we don't use the one the compiler comes with). I also work a lot with network protocols, though I don't personally like those quite as much.
wareya wrote: Things like dynamic arrays and variants should by all means be part of the language spec.
What exactly does this mean though? How exactly do you have data structures as part of the language?

A language, in terms of computing, isn't a runtime. They are two different things. A language is a set of well defined instructions to derive meaning from some form of input in a structured way. A runtime is how to execute some program. Technically, the c++ language standard gives no guidance on how to run a c++ program, only how to understand c++ code. It's up to the different programs that implement the language specification to provide a runtime.

In point of fact, I should point out that there are many more implementations of the C++ language than there are implementations of c++ runtimes. Any program that parses c++ code implement at least part of the language specification.
For example
  • Linters and security analyzers
    • covarity
    • lint
    • cppcheck
    • sonar
  • Code stylers
    • Clang format
    • Uncrustify
    • AStyle
    • UniversalIndentGUI
  • Syntax highlighters
    • Visual Studio Intellisense
    • KDevelop editor
    • SlickEdit
    • QtCreator editor
All implement at least part of the c++ language specification. From that list, none of them implement a runtime.

However, tools like
  • Metashell
  • Cling
  • ChaiScript
aren't compilers in the sense that they spit out libraries or executables, but they're interpreters and therefore provide some form of runtime on a conceptual basis, anyway. They very well may compile things internally, but that's an implementation detail.

C++, the language, is a set of well defined rules on how to take the textual code that a programmer feeds the compiler and and understand what that code means. How does the concept of dynamic arrays (Dynamically allocated? Dynamically sized?) and variants (Runtime? Compile time? Polymorphic?) have anything to do with a description of how to understand c++ code as written?
wareya wrote: For some reason they're not. I don't know why they're not, but it's insane to consider dynamic arrays and variants to be extensions of a program instead of extensions of the language.
I'll tell you exactly why they aren't. Because the core C++ language, by intention of the standards committee, should contain only the details necessary for a c++ compiler/interpreter/parser to understand the written code. Extending the syntax of the language is only done when it's necessary to provide functionality that industry experts believe will be widely used by developers. Generally, things are only actually included in the language standard when at least a few compilers implement the new feature. Once the meaning of the c++ syntax is changed in such a way that programmers can take advantage of the new way of explaining what the programmer means, library code can be created that explicitly takes advantage of those new syntactic capabilities.

The C++ Standard Template library is provided as a convenience to developers as a set of well written, lightweight, performant, functions and concepts. And I do mean "as a convenience". There are plenty of organizations that don't use the standard library as described by the c++ standard, or as provided by compiler vendors.
wareya wrote: Again, I do think this is stupid, and those things should be part of the language, not the standard library, but that's the way things stand right now.
I 100% disagree with you on this point.

As a personal note, I wish the c++ standard were broken up into two parts, instead of the big document it is now. I wish they'd have a document describing the language, as it's own standard, and another document for the standard library. I wish this because it would allow the core language to evolve at a much faster pace than we see now, not beholden to the pace of evolution of the standard library. Contrawise, I wish to see the standard library evolve at it's own pace, not beholden to the pace of evolution of the language itself. This is how it used to be, before the STL was incorporated into the standards document.

Mostly I desire that because I think it's frustrating to wait for standard library features that don't rely on syntax changes in any way until a full blown release. Were the process for the standard library and the core language decoupled, I feel like we would see much swifter evolution of the overall language community. Heck, most of the time compiler authors and STL maintainers are different people who hardly coordinate anyway. They really are two different beasts.

In the other direction, various recent conversations of the standards committee are somewhat worry-some to me, such as discussions over whether to include a graphics API into the standard library, or a file-system API.These are simply concepts that don't belong in the language, nor in the standard library, because they aren't universally applicable. Sure, sure, a lot of organizations would use them, but not all and probably not even most.

Threads? Literally every development organization in existence should be using the standardized thread functionality from the STL for any program bigger than their thumb. I'm glad to see this kind of functionality provided by the STL. But it certainly shouldn't be a part of the language unless there ends up being something that simply can't be done by code. The compiler doesn't fundamentally need to understand threads, at least not for what we're doing right now. I'm sure a good argument could be made though, if someone wanted to.

Threads are one of the reasons why it's awesome that the core language now has generalized attributes. These allow compiler plugins to provide special meaning for various attributes that allow the developer to customize the behavior of the compiled code. Maybe you have a great idea for an attribute that lets you catch coding patterns that result in bad performance? Maybe you have a very specific workflow that needs to be used with your code framework or you'll get runtime errors? Maybe you want to engineer a NEW way to do cross-language APIs? Generalized attributes to the rescue! One example is that I occasionally work on a media processing framework where certain tasks always need to happen on certain threads, with very few situations where a given function can be executed by different types of threads. Normally any given function is specific to a specific kind of thread. Generalized attributes to the rescue! If you call a function with threadX attribute from a function with threadY attribute, you goofed! New compiler warning. Saves lots of debugging time.

Atomics? The C11 (Not c++11) style atomics were a mistake. The C language introduced a new syntax to describe the concept of an atomically accessed region of memory. Sure, they partially borrowed syntax ideas from C++ to do it (basically they created poor-mans templates), but C++ has been able to provide identical atomic variable functionality with existing, well defined, c++ syntax since the 80's as application level code. Yea of course someone had to write code that would do the atomic memory operations, either with assembly or compiler intrinsics / built in functions, but providing atomic read/write memory operations in c++ didn't require a change to the language syntax. In fact, I had to implement this for work without being able to use the C++11 atomics stuff 2ish years ago. It's basically API compatible with what C11/C++11 decided on, and I did it with a C++98 compiler.

In C++11, the somewhat newly adopted atomic variable support was almost entirely added STL code. Of course, there were some changes to the way existing syntax was understood by the language, such as providing detailed explanations of the way memory access operations are ordered or allowed to be scheduled, but those neither introduced new syntax, nor did any code that wasn't somehow exploiting undefined behavior break by this change is meaning. To be honest, the way they redid the wording of the standard simply made the standard describe what compilers had already been doing anyway, for the most part.

But a graphics API? The way we've written graphical interfaces has changed every couple of years. Including these kinds of concepts into the core language doesn't make any sense. All they would be doing is copying an existing graphics library and renaming it as an STL module. Why bother.


Anyway, I'm getting off topic.

If the concept of an array that can have it's size change at runtime was introduced into the language itself, how would you represent that?

Right now we have c-style arrays. In GCC, as a compiler extension, you can even have c-style arrays where the size of the array is determined at runtime. That's great! But the size cant be changed after it's created.

How would you change the size of one of those after the fact? Depends on what you're doing, I suppose. If you kept things entirely on the stack, you could just change the stack pointer around. But that limits you to ONLY one dynamically growable / shrinkable array per function, otherwise only one of them could grow (The other would step all over the first). Then, how would you go about returning a dynamically growable array from a function? It's not a simple thing to do, the function that calls your function needs to pre-allocate the space on the stack for the returned value. I suppose that if the calling function itself doesn't have a dynamically sized variable that it would be able to take any arbitrary sized return value. But the called function must return the size of the returned value if it's not known at compile time. How does it do that? A size_t? Well that's 8 bytes on a 64 bit platform. Kind of expensive to copy that if you've only got 2 items in your array.

One could work around some of these issues by requiring conformant implementations to have multiple function stacks, or some standardized scratch space, but that runs contrary to how most CPUs are designed right now. We'll run into some performance problems when using multiple stacks

After you've added grown these dynamically sized arrays that are fundamentally part of the languages syntax past a certain level of sophistication, you simply can't add any more features without incorporating the concept of allocating memory. Having multiple stacks, after you get to a certain level of complexity, is basically identical to the concept of malloc/new and storing things on the heap.

Here's where we're going to have a problem. Allocation of memory is not part of the core language syntax. It's part of the standard library. Yea, there are some cross connections here, such as the new function being part of the language in the sense that it's a "keyword", but ultimately it just calls a function, and the function has to be defined as code provided to the compiler, it's not part of the compiler itself.

So you end up where your newly designed dynamically re-sizable array has to allocate memory. You could define a "standard" way to do this, in terms of behavior dictated by the standard, but I know that my employer would be ticked off. We heavily customize the allocator for various data structures to suit the performance needs of the code in question. If it's built into the compiler, how could we customize it?

Since it's not currently built into the compiler, we don't have to worry about it. We just don't even use the default, we built our own. We're very happy using our own version of dynamically sized arrays (aka, std::vector).


Ultimately, the solution is to keep the syntax of the language as small as is reasonable, and still provide with extreme power, extreme performance, and "only pay for what you use". Anything that isn't conceptually and fundamentally required to be a syntax concept is best left as described in terms of the c++ language as runtime / library / application code.

I don't want data structures built into the language. Struct/class and union are perfectly sufficient.

Struct/class describes the concept of "These things with these names aggregated side by side", union describes the concept of "These things with these names, but only one of them at a time, and all sharing the same memory location with as little extra space as possible".

Even union isn't the basis of much of the c++ language. I'd say that the majority of the functionality of union could be implemented at relatively low development time cost by simply casting "chat *" to "yourtypehere *" wherever you needed to. Point of fact, I do this all the time in my professional life.

With struct and union, and the other fundamental building blocks of the core language syntax, you end up with a language that's extremely powerful and flexible. The standard library is simply one example of the awesome amount of things that can be expressed in terms of the C++ language, and if you want to use it in your work that's awesome! But the STL is optional! You can implement a version of it yourself, or you can go your own way and build your own library basics. Up to you.

But please don't ask for things to be part of the language itself that can so easily be implemented in a library, that would cause me a huge amount of pain at work.
Mishtal
Posts: 28
Joined: 13 Dec 2016, 06:45

Re: C vs C++

Post by Mishtal »

Jyby wrote: The real pain is converting C to C++ in legacy projects. Imagine the 15 million line Linux Kernel converted to OOD with C++... What a pain in the ass. My company is in the process of doing this now for one of our products.
The great thing about the C++ Standard working so hard to maintain compatibility with the C language is that for many projects, you can massage your C code to the point where it's compile-able both with C and with C++. Once you've gotten your project to that point, you can have a flag-day and drop C in favor of C++ in terms of compiler setting.

Once you're compiling your "C" code as C++, no need to re-write any code! Just use the newly available (to you) C++ syntax where it makes sense, but otherwise keep your existing code how it is. Maybe rewrite a handful of structs as a polymorphic class hierarchy every now and then when it makes sense. Or merge 3-4 similar functions into a template function when you need a 5th version, that type of thing. Take it slow!
User avatar
wareya
Posts: 338
Joined: 09 May 2015, 13:07

Re: C vs C++

Post by wareya »

I'm not going to read all that, sorry. I have enough to do as it is.
Mishtal
Posts: 28
Joined: 13 Dec 2016, 06:45

Re: C vs C++

Post by Mishtal »

ezze wrote: Sure it's stupid that int a[5] passed to a function decays to a pointer, but you should use std::array and not think about it.
It only decays to a pointer to int if you pass it to a function that accepts a pointer to int.

You can also define a function that accepts an array of int. Either with a fixed size, or with a template parameter to determine the size during template instantiation. You accept the array parameter const ref, or by value. You can even accept a pointer to an array of fixed length, though you'll need to take the address of the variable when you call the function.
sirherrbatka wrote:
Besides, many of the worst stuff in C++ come from its compatibility with C,
I disagree. Does stuff like:

Code: Select all

int foo(int a)
{
 return a;
}

class foo
{
 public:
  foo(int a);
};

int main()
{
 something(foo(5));
}
Comes from C? Does glaring hole in templated constructors does? Lack of any higher level control over templates? Symbol mangling? Preprocessor is not everything.
C++11 unified initialization syntax allows you to disambiguate.

My reading of the code is that I would expect it to always call the function foo, not try to construct the object of class foo. Personally I don't think of this as ambiguous code.

sirherrbatka wrote:
Actually, I am fairly sure it comes from the C name spaces of identifiers so... yeah?
Nah, they could just have keyword new alongside, let's say, create. One allocates on heap, another on stack. But nobody thought about that.
About the "glaring hole" you are speaking of gotw 76? I never honestly saw the problem, when you are extending the interface to a new type accessing the privates becomes normal.
Nope. I wast talking about that:

Code: Select all

class foo {
 public:
  template<typename S>
  foo() {};
};
Now please try to use this constructor. There is no syntax to do so. This is what i mean by saying that C++ is badly designed language: it even has undeterministic syntax. You simply can't parse C++ and be 100% correct because nobody can ever be correct when parsing C++. And there is a lot of other design mistakes.

In Visual Studio, at least, this worked at some point or another. Other compilers may not support it. Note: Didn't bother trying to compile it, I just wrote it from memory.

Code: Select all

foo create_foo(void)
{
    char buffer[sizeof(foo)];
    foo& var = reinterpret_cast<foo&>(buffer);
    var.foo::foo<int>();
    return var
}

Chris wrote: Depends. On certain systems, premade support libs that have the C++ runtime as a dependency can be a problem with deploying binaries. For instance, I once proposed changing OpenAL Soft to C++, in part because of Microsoft's continued horrid support for non-ancient C standards. The response I got back from other developers was an astounding "Please Don't", because if an app is distributed as a binary that uses its own packaged C++ runtime, and it links to OpenAL which pulls in the system's C++ runtime, Very Bad Things can happen.
A solution to that would be to keep the C language API/ABI for the OpenAL library, but internally use C++ language features. No need to link the STL to your library to get benefits from the improved syntax capabilities.

Chris wrote:
The issue with C++ libraries is that the C++ binary ABI is unstable. Any respectful C++ library will only link over the C ABI.
Like the C++ standard library? :? If the language's own standard library can't avoid its pitfalls, what do you expect out of the language's users?
A given compiler's C++ ABI is stable over time.
Sorry, I mean the ABI of C++ libraries. Yes, the general C++ ABI itself is set.
But the C++ ABI isn't unstable at all? The same code + the same compiler == the same ABI every time. The same code + the same compiler but a different version will *probably* be the same ABI. The compiler vendor will happily document for you which versions are ABI compatible. There's nothing unstable about any of this, it's extremely predictable.

If you change the code for a library, of course the ABI breaks. The library is being compiled down to machine code, there's not much you can do to maintain compatibility auto-magically. As previously discussed there are plenty of work-arounds, but that doesn't inherently make the ABI unstable. It changes when one would expect it to change.
Chris wrote:
Every library "extends the language".
No. The basic purpose of a library is to extend your program, not the language.
It extends your program's capabilities by extending the language functionality. If you write a program in C++, you can only do what C++ allows you to do, full-stop. If your program can do more, you've extended C++ to let you do more. Like threading. Prior to C++11/C11, you needed to use something like libpthread, which extends the C++/C language with threading functionality. You extend the language by including that library and you can then use threads through C++/C (in this case, the functionality was useful enough across so many types of software that it ended up in the core languages and no longer needs an extra library). Similar to audio, the core C language does not define any audio functionality, so you get a library like SDL or OpenAL that adds it to the language, then your program can use audio through C.

libpthread doesn't extend the language with threading functionality, it provides a set of functions that interact with the operating system's API, and the underlying hardware that can be used to get certain runtime behavior. Ultimately, all libpthread does is provide a blob of machine code and other associated data that is structured in a way that when it's linked into a program at runtime, can be called and executed. libpthread happens to allow your program to execute in multiple threads, but that's neither here nor there when it comes to the question of if it extends the language or the program. It doesn't extend either, it's simply code.

Even in c++17, there is no "thread" as a concept in the c++17 *language*, meaning the syntax and the meaning of that syntax. Of course, there are threading features in the STL now, but that's just a library that uses the c++ language to convey meaning to programs that implement the language standard.
Post Reply