Hot answers tagged

110

Strangely, the history of C-style programming language doesn’t start with C. Dennis Ritchie explains well the challenges of C’s birth in this article. When reading it, it becomes obvious that C inherited a part of its language design from its predecessor BCPL, and especially the operators. The section “Neonatal C” of the aforementioned article explains how ...


103

Basically because the designers of Java and similar languages didn't want undefined behavior in their language. This was a trade off - allowing undefined behavior has the potential to improve performance, but the language designers prioritized safety and predictability higher. For example, if you allocate an array in C, the data is undefined. In Java, all ...


72

Undefined behaviour is one of those things that were recognized as a very bad idea only in retrospect. The first compilers were great achievements and jubilantly welcomed improvements over the alternative - machine language or assembly language programming. The problems with that were well-known, and high-level languages were invented specifically to solve ...


68

CI-driven development is fine! This is a lot better than not running tests and including broken code! However, there are a couple of things to make this easier on everyone involved: Set expectations: Have contribution documentation that explains that CI often finds additional issues, and that these will have to be fixed before a merge. Perhaps explain that ...


59

Argv is basically like this: On the left is the argument itself--what's actually passed as an argument to main. That contains the address of an array of pointers. Each of those points to some place in memory containing the text of the corresponding argument that was passed on the command line. Then, at the end of that array there's guaranteed to be a null ...


49

I cannot think of a reason why the designers chose to deviate from the principle that single is bitwise and double is logical here, That's not the principle in the first place; once you realize that, it makes more sense. The better way to think of & vs && is not binary and Boolean. The better way is to think of them as eager and lazy. The &...


48

Calling a class method with some class variables is not necessarily bad. But doing so from outside the class is a very bad idea and suggests a fundamental flaw in your OO design, namely the absence of proper encapsulation: Any code using your class would need to know that len is the length of the array, and use it consistently. This goes against the ...


42

Undefined behavior enables significant optimization, by giving the compiler latitude to do something odd or unexpected (or even normal) at certain boundary or other conditions. See http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html Use of an uninitialized variable: This is commonly known as source of problems in C programs and ...


35

No, not at all ! Abstractions and good practices can of course reduce the risks of errors. For example: language abstractions let the compiler generate code, that you would have to write yourself otherwise. For example, the C++ object model ensures that object constructed are destroyed as they supposed to be, without extra care on your shoulders; these ...


34

Building a sustainable plugin model requires that your core framework expose a stable interface that plugins can rely on. The golden rule is that you can introduce new interfaces over time but you can never modify an already published interface. If you follow this rule, you can refactor the implementation of the core framework all you want without fear of ...


34

I think you are misrepresenting the message of the "Modern C++ in Embedded Systems" video. The point is that there are people in the embedded world that write code and then test it by running the code in the debugger to verify that it does what they think it does. He argues that a better alternative is to use abstractions so that the compiler can verify that ...


33

There are may things with the class that I would do differently, but to answer the direct question, my answer would be yes, it is a bad idea My main reason for this is that you have no control over what is passed to the add function. Sure you hope it is one of the member arrays, but what happens if someone passes in a different array that has a smaller ...


24

It varies slightly with the architecture, but the important points apply nearly universally: Interrupt servicing causes the CPU state (including registers) to be saved to memory before running the ISR, and restored as the ISR exits. If an interrupt service routine swaps the content of the memory location where those registers are saved, it can perform a ...


22

Because that's what the operating system provides :-) Your question is a little bit of a chicken/egg inversion issue. The problem is not to choose what you want in C++, the problem is how you say in C++ what the OS is giving you. Unix passes an array of "strings", each string being a command argument. In C/C++, a string is a "char*", so an array of ...


22

This question basically boils down to "can you write bug free code the first time every time?” The answer is always going to be no. Yes, there are practices that can help, you can isolate modules. You can compile both for the embedded and desktop, then test and develop on the desktop. You can create hardware abstraction layers that help isolate those ...


21

TL;DR C inherited the ! and ~ operators from another language. Both && and || were added years later by a different person. Long Answer Historically, C developed out of the early languages B, which was based on BCPL, which was based on CPL, which was based on Algol. Algol, the great-granddaddy of C++, Java and C#, defined true and false in a way ...


20

In C's early days, there was a lot of chaos. Different compilers treated the language differently. When there was interest to write a specification for the language, that specification would need to be fairly backwards-compatible with the C that programmers were relying on with their compilers. But some of those details are non-portable and do not make sense ...


16

In a big C++ project I would like to have a mechanism [...] to prevent such data in most parts. There is such a mechanism. It is called code reviews - especially when done by the experienced guys in your team. Use that, and you will sucessfully avoid any unnecessary global variables in your project. (And yes, I am aware that is probably not the answer ...


15

First, as a parameter declaration, char **argv is the same as char *argv[]; they both imply a pointer to (an array or set of one or more possible) pointer(s) to strings. Next, if you only have "pointer to char" — e.g. just char * — then in order to access the nth item, you'll have to scan the first n-1 items to find the nth item's start.  (...


15

C++ has a rule about overridden functions: they don't have to be explicitly declared as virtual. Consider your example without override: double getAge(int id);. If there is a base class function declared virtual, named getAge, and takes the same parameters as the derived class function, then the derived class function will implicitly be virtual and it will ...


14

When the compiler goes to execute the implicit delete _ptr; inside of the unique_ptr's destructor (where _ptr is the pointer stored in the unique_ptr), it knows precisely two things: The address of the object to be deleted. The type of pointer which _ptr is. Since the pointer is in unique_ptr<base>, that means _ptr is of the type base*. This is all ...


14

In addition to the great information by @BenVoigt, allow me to make some additions: A breakpoint is set by the debugger by replacing a machine code value (an instruction or part of an instruction) in the process being debugged with a particular trap instruction at the location in code that corresponds to the desired (source) line to break at.  This ...


14

JVM and .NET languages have it easy: They don't have to be able to work directly with hardware. They only have to work with modern desktop and server systems or reasonably similar devices, or at least devices designed for them. They can impose garbage-collection for all memory, and forced initialization, thus getting pointer-safety. They got specified by a ...


13

Why C/C++ main argv is declared as “char* argv[]” A possible answer is because the C11 standard n1570 (in §5.1.2.2.1 Program startup) and the C++11 standard n3337 (in §3.6.1 main function) require that for hosted environments (but notice that the C standard mentions also §5.1.2.1 freestanding environments) See also this. The next question is why did the C ...


13

This is going to be a frame challenge, because I disagree with the underlying notion that the character count of your code is the most important metric for code quality, or that templates are the best way to write code faster. Disclaimer: This is written from the perspective of a (predominantly) C# developer, but the argument I'm making is language agnostic....


12

Rather than thinking of it as "pointer to pointer", it helps to think of it as "array of strings", with [] denoting array and char* denoting string. When you run a program, you can pass it one or more command-line arguments and these are reflected in the arguments to main: argc is the count of arguments and argv lets you access individual arguments.


12

Each time a process produces output, it has to call a function that actually does the work. In most cases, that function is ultimately write(2). On a multitasking operating system, the call to write() will trap into the kernel, which has to stop the process, handle the I/O, do other things while any blockages are cleared, put it on the ready queue and get ...


12

Addressing the question about cleanup code: yes, there is a way, it's called RAII (for Resource Acquisition Is Initialization, an acronym whose limpid clarity is rivalled only by CRTP), and it is both idiomatic and highly recommended (eg, by the C++ Core Guidelines) You'll see there is built-in support for RAII for some common types in the form of std::...


11

You've already gotten answers pointing to why it's not necessary for all iterators to inherit from a single Iterator base class. I'd got quite a bit further though. One of the goals of C++ is abstraction with zero run-time cost. If iterators worked by all of them inheriting from a common base class, and used virtual functions in the base class to define the ...


Only top voted, non community-wiki answers of a minimum length are eligible