4 ms·
From my experience, maintaining a standalone/embedded printf library - MISRA is a combination of two things: Common-sense rules, and pain-in-the-ass rules. The
by einpoklum 3y ago
From my experience, maintaining a standalone/embedded printf library - MISRA is a combination of two things: Common-sense rules, and pain-in-the-ass rules. The former are not very interesting and you probably have them in your head as coding guidelines anyway; but the latter, well, are a pain.
Example: Avoiding implementation-defined types like `int` _every_where, even in places where my code doesn't care about what sizeof(int) is; or when I want to store the result of a system call which returns an int.
I was able to accommodate most (?) of the MISRA rules (https://github.com/eyalroz/printf/issues/77 https://github.com/eyalroz/printf/issues/77), but mine is just a small library, so I don't know how restrictive they would be for a larger codebase. I suspect it would be painful and force you to avoid some legitimate and useful coding patterns.
- IshKebab 3y ago> Avoiding implementation-defined types like `int` _every_where Well that is the correct thing to do. I guess you can't really complain to MISRA about C being crazy.
- jjnoakes 3y ago> Well that is the correct thing to do. Is it? I can think of quite a few cases where using 'int' is fine; why is that a problem?
- archi42 3y agoCross-platform code - Is your int still 16 bits on your new CPU? Of course you know* your variable is always between 0 and 15, but the MISRA checker might not**. Today we have int16_t et al., so this is much less of an issue. *) IME "know" is often merely a "believe". **) Not sure that even if you have a MISRA checker that has a suitable inference, it is allowed to discard alarms on this kind of violation. I wrote MISRA test cases for something for a suitable powerful checker/analyzer, but I can't remember this detail anymore.
- usrnm 3y agoWhy do you think that believing that sizeof(int) == 4 is worse than believing that int32_t exists? It doesn't have to
- ska 3y agoIf a type doesn't exist in your toolchain, your compile will fail an you will know why. Conversely, incorrect assumptions about size/size/capacity can lead to subtle run-time bugs.
- deleted 3y ago[deleted]
- archi42 3y agoYou have to check sizeof(int) somewhere. Why not do that in a header? To make sure you're using the checked int, define a new type, eg "int4" in that header, too, and use that. Congratulations, you'll fulfill this MISRA rule :) Or just use int32_t and let the compiler fail if your Toolchain does not have that. Then just write an appropriate header to add it (with the correct checks) ;)
- astrange 3y agoIf you know your variable is between 0 and 15 and care deeply about this, I kinda think you should get explicitly-ranged integer types added to your language rather than use a type that's defined for -32767 - 32767 but doesn't enforce it. Also, IME it obscures bugs in your code if you're forced to overspecify things, because now someone reading it has to determine if all those explicitly specified details are actually correct or not.
- IshKebab 3y agoDefinitely! But MISRA is about writing robust code with an error-prone language, not picking a different language that is better designed. Your second point doesn't make any sense. Someone reading `int` has to determine if that is actually correct or not too.
- nicoburns 3y agoI can think of lots of cases where carelessly using int might cause issues. And none at all where it's actually better than using a different type. Aside from anything else, it's probably better to default to unsigned types. I'm fully willing to believe that MISRA-C contains a lot of silly, unnecessary rules, but IMO this isn't one of them. If typing out uint32_t, etc is too long, then you can always create an alias.
- astrange 3y ago> it's probably better to default to unsigned types. Security teams at our company have told me this too but I absolutely disagree. If you're going to write in C, and you don't want your variable to overflow, then you should use a type that doesn't have defined overflow semantics. The reason for this is that it makes it easier to find bugs, because you want to discover wrong behavior rather than just define it to do an arbitrary wrong thing. You can do this with UBSan. In fact, as long as it's okay for your code to crash, I endorse shipping it with UBSan turned on. (Presumably this isn't the case for a car MCU though. Don't ask me what to do there.)
- IshKebab 3y agoIn practice the arbitrary sizing of basic C integer types (int, long, etc.) has proven to be extremely error prone. Basically it's virtually impossible to use them correctly (except in small examples). You don't get any portability benefits because it's too difficult to write code that is actually portable across word sizes, and you get extra bugs when things don't behave like you expect. There's basically no upside. It's much less error prone to use fixed size types, especially since approximately all computers are now 32 or 64 bit. I once lost hours on an Arduino project exactly because of this. I was using the SD card library, and there was an infinite loop bug. Turned out to be because most Arduinos (at the time) are 16 bit, but I was using a 32 bit one. The code had been written using `int` but also assumed that int was 16 bits! The code was less portable because of the "portable" int sizing system. It didn't work at all with other sizes, whereas if it had been written using uint16_t it would have worked fine. You can say "well they made a mistake", but remember we're talking about MISRA. Avoiding mistakes is the whole point.
- ska 3y ago> I can think of quite a few cases where using 'int' is fine; why is that a problem? It's a problem when your toolchain or target changes, and assumptions you were making (explicitly or implicitly) about 'int' now fail in difficult to understand ways.
- jjnoakes 3y agoLots of replies kind of missed my point (my fault, probably) - I think there are cases where 'int' is the correct type to use, and cases where it is not. I think using 'int' everywhere is probably a mistake, and using 'int' nowhere is probably also a mistake. Sometimes you are working within the guaranteed bounds of an 'int' in the C standard, so portability isn't an issue. Sometimes you are mixing different types and want to capture intermediate values in the promoted type, which is dictated by the C standard. Sometimes you want to use the native machine word for a good reason. And sometimes it is just easier to read and reason about (printf-like conversion specifications, code that interfaces with POSIX APIs frequently, etc).
- AlotOfReading 3y agoThe relevant MISRA rule (which is advisory, not mandatory) includes avoiding size_t, which is absolutely the correct type to use in a lot of pointer situations.
- MaxBarraclough 3y agoDo you have a source for that? From a quick Google it doesn't seem to prohibit size_t. Rule 3-9-2 (which is only advisory) says Typedefs that indicate size and signedness should be used in place of the basic numerical types, but this doesn't prohibit use of size_t. https://forum.misra.org.uk/thread-1130.html https://forum.misra.org.uk/thread-1130.html
- AlotOfReading 3y agoI didn't say it prohibited size_t, only that it suggests avoiding it like other variable-sized types. In practice, compliance checkers will turn advisory rules into warnings, which means every usage of a size_t can potentially become a warning message. It's a lot of unnecessary noise for writing correct code.
- IshKebab 3y agoRead his link.
- FirmwareBurner 3y ago>you probably have them in your head as coding guidelines anyway Ha, if only. Sure, if everyone working on the project is a skilled C dev then yeah, but not when you're piecing together code form a bunch of bodyshops as it often happens in automotive where everything is contracted out to the lowest bidder to push costs down, so MISRA is there as a minimum common denominator to make sure that your code doesn't reach rock bottom in the process.
- einpoklum 3y agoOk, fair enough, I'm relatively skilled and I've taught C (and some C++) to people, so I guess I'm biased. On the other hand - extensive compiler warnings + non-MISRA general-purpose static analysis would probably cover those.
- gte525u 3y agoFWIW - usually when interfacing with foreign code like that you match what the foreign code's types than convert it afterwards. Then add an assert [sizeof(t1) >= sizeof(int)] or better a static_assert. The intent isn't to make your code bullet-proof. It's to move towards a subset of the language with well-defined semantics. Any safety critical coding standard work I've done always had a waiver process for both MISRA and mccabe-like complexity requirements - the intent is there's always some point where there is diminish returns for compliance.
- NovemberWhiskey 3y ago>always had a waiver process for ... mccabe-like complexity requirements Also known as "the one trick that your test team doesn't want you to know".