New answers tagged

-2

The preprocessor has already given meaning to newline characters. You can't completely undo that at a higher level. Compare: char s1[] = "This is how macros work in C\nExample\n #define IS_GOOD 1\n"; with char s2[] = "This is how macros work in C Example #define IS_GOOD 0 "; Clearly the second is easier to read (in a hypothetical C compiler ...


-2

Wikipedia has an entry with some details: Two problems with multiline string literals are leading and trailing newlines, and indentation. If the initial or final delimiters are on separate lines, there are extra newlines, while if they are not, the delimiter makes the string harder to read, particularly for the first line, which is often indented ...


-2

I cannot answer on the "why"; as far as I know language designers tend to copy the "bad stuff" as many times as the "good stuff" when designing a language based on other languages. I do have to say that using RegEx to parse your code is not the best way to do it and writing a parser which can keep track of multiline strings might be harder than you would ...


3

FWIW, Ocaml accepts a limited form of multi-line string literal : String literals are delimited by " (double quote) characters. The two double quotes enclose a sequence of either characters different from " and \, or escape sequences from the table given above for character literals. To allow splitting long string literals across lines, the sequence ...


9

What happens when you didn't mean to have a multi-line string, but instead forgot to close the quote? The parser will chew through the code until it hits another quote in a completely different part of the program, then proceed as normal. This will very likely lead to confusing, unrelated errors since the string is no longer the parse error. At worst, you ...


2

As someone who uses this idiom in some contexts — although I generally put \n at the end to ensure flushing —, I can offer a justification: I tend to use this when formatting many lines, especially if starting with an empty line, so that the \ns are aligned. This means that it is somewhat easier to (a) check that all lines do indeed include a \n or (b) to ...


1

The relevant documentation is called the Application Binary Interface (ABI) and the calling conventions. Both are processor and operating system specific. Read the x86_64 Linux ABI. See also syscalls(2) for the available system calls. Almost every system call has its man page in section 2. BTW, chmod(2) does list various symbolic constants like S_ISUID, ...


8

From http://www.jslint.com/chistory.html ("The Development of the C Language" by Dennis M. Ritchie): Many other changes occurred around 1972-3, but the most important was the introduction of the preprocessor, partly at the urging of Alan Snyder [Snyder 74], but also in recognition of the utility of the the file-inclusion mechanisms available in BCPL and ...


3

The answer depends on the context of the question. If the context of the question is whether there is any way to do this without respect to the compiler, in a completely standard way without relying on undefined behavior, that works everywhere, then the answer is a clear and unambiguous "no". However with that said... In some contexts, it may be very ...


10

The compiler is only required to honor legal, valid constructs. Compilers have myriads of choices to make in code generation. Compilers have many, many ways of doing the same thing. If the difference between one choice or another can't be observed -- by the program, using only valid language constructs -- then it will generally opt for the more ...


2

Not legally. There is a good chance that after writing either p += 1 or p -= 1 or p += 2 or p -= 2 we find that p == &b. (All these assignments other than p += 1 invoke undefined behaviour). However, there is no way to read or write b using that pointer without invoking undefined behaviour. Therefore, the compiler may for example delaying the ...


12

No is the correct answer. However, seeing that both variables have been declared on stack right after each other, you might actually write p++ to maybe obtain the pointer to memory location where b is, if you are lucky. Note this is in no case safe and can never be relied upon, as it relies on undefined behaviour.


0

The thing with any form of testing is that in order for it to be worthwhile, when it finds defects, you have to fix them. While it is very easy to instead change your tests to match the buggy behavior, this invalidates the whole exercise. In this case, your testing has found defects: your internal functions have paths that are not reachable from tests of ...


2

Have you considered putting the functions into the module's header file, but putting them in a conditionally compiled block that is only enabled in build configurations that are tested? It would be analogous to having a C++ class with public and private functions. However, that's not a good option if you're shipping the header file to users, and want to ...


3

Unit tests are supposed to be for external functions only. Nevertheless, if you have a lot of "internal code", it should be tested too right? So how? Make smaller functions, separated from you code (another .c and .h), and use those functions as a library that can be unit tested. Then you should be able to test those functions that are used by the internal ...


1

Abstractions are necessary to manage complexity, which is the Nemesis of all programmers. It's just as important to learn using abstractions as it is to learn the details behind them. A solution to a real-world problem needs to have a representation that closely resembles the model of the problem. It's why a dice game has a class called Die with a method ...


0

As others have pointed out, everything is both an abstraction and a detail. The abstractions allow you to focus on understanding and manipulating the concepts involved while knowledge of the details allow you to implement them. To a solution architect, the progrmming language is just a detail, to a coder optimising a sort algorithm, a datatype is just an ...


2

here is one method to produce the desired results #include <stdio.h> int main( void ) { char n[3]={'A','B','C'}; int s[3][4] = { {90,50,100,10}, {60,100,20,50}, {80,70,100,75} }; //float average=0; int x; int y; //int max=0; //int min=0; //int total=0; // to print in 'column' order ...


2

What time is it? Is it time to become a know-it-all programmer or is it time to become a productive programmer? Knowing the abstraction layers that exist below those among which you work is a good thing, it grants you a better understanding behind the structure of your work and it will even allow creating better solutions. Yet, you do that, you study when ...


1

You might like to read Zen and the Art of Motorcycle Maintenance which addresses this very question. The conclusion that it arrives at is that you should aim to generate the greatest 'Quality' at the level(s) of abstraction that you choose. Sometimes this means understanding more about the levels above and below you, but generally you won't be able to master ...


0

As indicated in philipxy's answer, anything digital is an abstraction. Even the electrical engineering view of currents and voltages is an abstraction. I've worked as a computer architect, a compiler writer, and an operating systems developer. I have had the experience of writing Java programs I intended to run on a server I helped design. Cycle-by-cycle ...


3

The abstractions we teach in computer science are the things which, historically, have been found most beneficial to most people writing most programs. You can't write a modern program in assembly, just due to the sheer size of modern programs and the time constraints business will place on a developer. You have to be ready to accomplish your goals without ...


4

There are several benefits, the obvious one is at compile time to ensure that things like function parameters match the values being passed in. But I think you are asking about what is happening at runtime. Keep in mind that the compiler will create a runtime that embeds knowledge of the data types in the operations it performs. Each chunk of data in ...


1

On the other end of the spectrum is another book that often gets praised as a classic of how to teach algorithms: Donald E. Knuth’s Art of Computer Programming. DEK gave all his algorithms in a (fake, abstracted) machine language, because in his view, programmers will tend to write code that’s simple and efficient in the language they’re using, and the size ...


19

No, abstractions don't prevent you from understanding how things work. Abstractions allow you to understand why (to what end) things work the way they do. First off, let's make one thing clear: pretty much everything you've ever known is at a level of abstraction. Java is an abstraction, C++ is an abstraction, C is an abstraction, x86 is an abstraction, ...


5

I know why abstraction is great, but doesn't that prevent you from learning how computers work? Am I missing something? Go to a magic show and you'll be entertained but you won't understand how the tricks work. Read a book on magic and you'll learn how tricks work but you still won't be entertaining. Do both. Work hard. And you might be both. ...


3

Software engineering has multiple levels of detail. Your question is "what is the most rewarding, worthy, interesting level?" It depends on your task or on what you want to be, what you care about. For big systems you should not care much about bit shifting and clock cycles. For embedded software running on a simple micro controller you will probably want ...


40

Eventually, I thought you will become a better programmer knowing this because you'll know what's happening rather than assuming that everything is magic. These are not contradictory things. I have no idea how to pave a road, but I know that it is not magic. But a month ago, I came across this book called Structure and Interpretation of Computer ...


16

A key skill in programming is simultaneously thinking at multiple levels of abstraction. Another key skill is building abstractions; this skill uses the previous one. Low-level programming is valuable in part because it exercises and expands both these skills. SICP models and implements interpreters, simulators for a machine model, and a compiler to that ...


31

I know why abstraction is great, but doesn't that prevent you from learning how computers work? Certainly not. If you want to understand the abstractions at work, then study those abstractions. If you want to understand the low-level technical details of a real, physical, computer then study those details. If you want to understand both, study both. (In ...


-2

There can be many advantages to such code, but unfortunately the C Standard was not written to facilitate it. Compilers have historically offered effective behavioral guarantees beyond what the Standard required that made it possible to write such code much more cleanly than is possible in Standard C, but compilers have lately started revoking such ...


-3

Next step is to hide the struct declaration. You put this in the .h file: typedef struct foo_s foo_t; foo_t * foo_new(...); void foo_destroy(foo_t *foo); some_type foo_whatever(foo_t *foo, ...); ... And then in the .c file: struct foo_s { ... };


2

It's not bad, it's excellent. Object Oriented Programming is a good thing (unless you get carried away, you can have too much of a good thing). C is not the most suitable language for OOP, but that shouldn't stop you getting the best out of it.


0

It's not bad. It endorses to use RAII which prevents many bugs ( memory leaks, using uninitialized variables, use after free etc. which can cause security issues ). So, if you want to compile your code only with GCC or Clang ( and not with MS compiler ), you can use cleanup attribute, that will properly destruct your objects. If you declare your object like ...


23

No, this is not bad practice, it is even encouraged to do so, although one could even use conventions like struct foo *foo_new(); and void foo_free(struct foo *foo); Of course, as a comment says, only do this where appropriate. There is no sense in using a constructor for an int. The prefix foo_ is a convention followed by a lot of libraries, because it ...


-1

Yes it is possible to do TDD on embedded software. The people telling it is not possible, not relevant, or not applicable are not correct. There is serious value to be gained from TDD in embedded as with any software. They best way to do it though is not to run your tests on the target but to abstract your hardware dependencies and compile and run on your ...


1

for a repeating timer. Use setitimer() here is info from the man page NAME getitimer, setitimer - get or set value of an interval timer SYNOPSIS #include <sys/time.h> int getitimer(int which, struct itimerval *curr_value); int setitimer(int which, const struct itimerval *new_value, ...


2

First things first: The original K&R was written in 1978. Expecting that a book written in 1978 is authoritative now is a bad expectation. The C language was an offshoot of B, which in turn was an offshoot of BCPL. In B, the auto keyword was essentially the opposite of the extrn keyword. That is perhaps the best way to think of the modern C extern ...


4

There's numerous ways to acheive this, all depending on what kind of environment you're working with. Another concern is of course the latency you can afford. If you are working on a modern operating system, you most likely have an API that will put your thread to sleep until the given time has arrived. Posix has nanosleep() and C11 has the thread_sleep() ...


0

Cool your learning c, you just discovered one of c little tongue twisters. You are not doing pointer arithmetic on an array, but an array of pointers. Doing pointer arithmetic on arrays is not possible. An array decays to a pointer but is not a pointer type it self. What you my have (see comment by cmaster) is int *array[]; //This is a array to pointers ...


4

First (assuming C99 standard), you may want to include <stdint.h> standard header and use some of the types defined there, notably int32_t which is exactly a 32 bits signed integer, or uint64_t which is exactly a 64 bits unsigned integer, and so on. You might want to use types like int_fast16_t for performance reasons. Read others answers explaining ...


14

So, there are two things here: the language level: what are the semantics of C the machine level: what are the semantics of the assembly/CPU you use At the language level: In C: overflow and underflow are defined as modulo arithmetic for unsigned integers, thus their value "loops" overflow and underflow are Undefined Behavior for signed integers, ...


4

To further @StevenBurnap's answer, the reason this happens is because of how computers work at machine-level. Your array is stored in memory (e.g. in RAM). When an arithmetic operation is performed, the value in memory is copied into the input registers of the circuit that performs the arithmetic (the ALU: Arithmetic Logic Unit), the operation is then ...


24

Signed integer overflow is undefined behavior. If this happens your program is invalid. The compiler is not required to check this for you, so it may generate an executable that appears to do something reasonable, but there is no guarantee that it will. However, unsigned integer overflow is well-defined. It will wrap modulo UINT_MAX+1. The memory not ...


47

No, it does not. In C, variables have a fixed set of memory addresses to work with. If you are working on a system with 4-byte ints, and you set an int variable to 2,147,483,647 and then add 1, the variable will usually contain -2147483648. (On most systems. The behavior is actually undefined.) No other memory locations will be modified. In essence, ...


5

No one said unit tests have to be run all on the same platform - but no one said you could reach 100% test coverage either. As a first step, #ifdef out the code, preferably factoring it into a platform-specific function. Write a suitable implementation of this function for x86. However, I don't think it is appropriate to select the code to be compiled based ...


4

C is a low-level language, nearly a portable assembler, so its data structures and language constructs are close to the metal (data structures have no hidden costs - except padding, alignment and size constraints imposed by hardware and ABI). So C indeed does not have dynamic typing natively. But if you need it, you could adopt a convention that all your ...


8

You hit on one of the only reasons this is useful: mapping external data structures. Those include memory-mapped video buffers, hardware registers, etc. They also include data transmitted intact outside the program, like SSL certificates, IP packets, JPEG images, and pretty much any other data structure that has a persistent life outside the program.


2

What you have here is a Tail Call, and even more, it is Tail Recursion (Direct Tail Recursion) to be precise. Many languages have Proper Tail Calls (e.g. Scheme, ECMAScript), and even more languages have Proper Tail Recursion (e.g. Scala, at least for Direct Tail Recursion). Unfortunately, neither C nor Java support Proper Tail Calls or even the much weaker ...


0

The answers seem pretty consistent but missing an important point. You are telling the compiler that you want to to allocate space and for every access, read OR WRITE, you want it to perform that access. We dont want it to optimize away those accesses or that variable for some reason. Yes, one reason is because someone else might change that value for ...



Top 50 recent answers are included