0

I would like to ask you why in the following code the compiler doesn't give an error? This is the flash.h file:

#ifndef _FLASH_H_
#define _FLASH_H_
#define BANK_A    0
#define BANK_B    1
#define BANK_C    3
#define FLASH_IS_BUSY         (FCTL3 & BUSY)//FCTL3 and BUSY are defined in msp430f5438a.
#endif

And this is the main.c file:

#include "flash.h"
#include <msp430f5438a.h>
void main(void)
{
   while(1)
   {
      ;
   }
}

The problem is that I don't understand how the compiler doesn't give an error at this line:

#define FLASH_IS_BUSY         (FCTL3 & BUSY)

Since there is no way (according to my grasp) the compiler to know what FCTL3 and BUSY mean. These both macros are defined into the msp430f5438a.h as follows:

#define FCTL3  (*((unsigned char*)0x0144u))
#define BUSY   0x01  

But the flash.h is included before msp430f5438a.h How the compiler resolves those symbols: FCTL3 and BUSY?

Lundin
  • 195,001
  • 40
  • 254
  • 396
Radoslaw Krasimirow
  • 1,833
  • 2
  • 18
  • 28
  • 1
    macros are replaced at / before parsing time. so the compiler in theory doesn't see `FCTL3` and `BUSY` – Alexander Oh Jul 06 '15 at 10:47
  • A compiler cannot warn against all (or even most) possible mistakes. Read about [Rice's theorem](https://en.wikipedia.org/wiki/Rice%27s_theorem) & [Halting problem](https://en.wikipedia.org/wiki/Halting_problem) – Basile Starynkevitch Jul 06 '15 at 10:51

3 Answers3

4

The thing here to notice is, the #defines work as textual replacement at the preprocessing stage, they are not the same as variable declaration or definition.

In your header file, you have only defined the FLASH_IS_BUSY MACRO, but in your code, you've not used that. Even, if you've used that, before the main(), the header #include <msp430f5438a.h> is there, which makes the definition of FCTL3 and BUSY available to your code, if used.

TL;DR The FLASH_IS_BUSY macro definition in the header file does not need FCTL3 and BUSY to be defined already. For example, you can supply these MACRO values with -D option with gcc, they need not appear in the code, at all.

That said, the recommended signature of main() is int main(void)

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    msp430 is a microcontroller, so `int main (void)` is most likely incorrect and bad. – Lundin Jul 06 '15 at 11:12
  • @Lundin Huh? `int main(void)` is one of the signatures required by standard C. A microcontroller has no command line, so `int main(void)` what makes the most sense, the other alternative being `int main(int, char**)`. – Potatoswatter Jul 06 '15 at 11:32
  • @Lundin sir, in my defense I would like to raise two points . 1) the question was not tagged with `msp430` or such, but only with `C` and 2) the _case_ in question has no direct relation with that, so the tag is not required either, the last line was just a suggestion, for C standards. That's all. Hope I am not misunderstood. :-) – Sourav Ghosh Jul 06 '15 at 11:35
  • ok, anyone is willing to help me by sharing some pointers for the reason for down-vote, please? – Sourav Ghosh Jul 06 '15 at 11:40
  • 1
    @Potatoswatter Freestanding implementations have a completely implementation-defined signature, see 5.1.2.1. – Lundin Jul 06 '15 at 12:00
  • @SouravGhosh It wasn't tagged as such but it is blatantly obvious, at least to me. Either from an embedded systems or from a generic C point of view, your recommendations about main are still incorrect. – Lundin Jul 06 '15 at 12:03
  • @Lundin Hosted implementations can have an implementation-defined signature too, see 5.1.2.2.1. – Potatoswatter Jul 06 '15 at 15:32
2

Limiting to specific topic of your question (preprocessor substitutions), with this:

#define FLASH_IS_BUSY (FCTL3 & BUSY)

You're not using FCTL3 and BUSY in any way. You're just instructing compiler to perform a textual replacement. It has no need to know anything about them.

However when you use it in your code like this:

int flags = FLASH_IS_BUSY;

It'll perform a first replacement:

int flags = (FCTL3 & BUSY);

Replacement loop will continue until there is something to replace (or hard threshold is reached). If you forget to include msp430f5438a.h then above code won't simply compile (because FCTL3 and BUSY are unknown), however if you included right header file (no matters in which order: msp430f5438a.h first or flash.h first) they'll be replace by preprocessor with their actual values and you'll have right code:

int flags = ((*((unsigned char*)0x0144u)) & 0x01);

Now preprocessor finished and compiler (when optimizations are enabled) will (may!!!) directly replace flags with literal value.

Notes:

  • Your main() signature is non-standard. It should (for hosted environments) be int main(void) or int main(int argc, char* argv[]). See also What is the proper declaration of main?. Note that if your compiler allows void main(void) signature then it's not wrong but it's just non-standard. However Lunding highlighted that in freestanding environments main() function, according to C standard, signature is completely implementation-defined. See his enlightening post: Why is the type of the main function in C and C++ left to the user to define?
  • I understand while(1) is only illustrative (and it's not your real code) but it may be UB in earlier C specifications. I won't repeat here this (long) discussion then please refer to Are compilers allowed to eliminate infinite loops? for further researches.
  • u suffix isn't necessary, in C integer literals are always non negative then u is just redundant. However it may be required by some specific guidelines (for example in critical systems, see MISRA) to make explicit (to readers) that a constant is intended to be a non-negative integer.
  • Your empty loop may be simply optimized away. Compiler is free to do not generate any code for ;. Various workarounds exists if you want to make it portable.
Community
  • 1
  • 1
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • Could you please elaborate a bit about while(1) problem (in aspect of pre-C99 standard specifications)? As to why it is considered UB? – HighPredator Jul 06 '15 at 11:10
  • msp430 is a microcontroller, so `int main (void)` is most likely incorrect and bad. Since it is a freestanding system, `void main (void)` is just fine and 100% standard-compliant. – Lundin Jul 06 '15 at 11:24
  • @Lundin I didn't write it's _wrong_ or it's an _error_, I wrote _"...signature is non-standard."_. I stress on **non-standard**, almost every compiler allows void main(void) but it's a **compiler extension**, not what standard says. However what will happen if you return from main() in a microcontroller is absolutely undefined. Jump back? Execute garbage? Hang? If you have an explicit return value you (at least) save yourself from simple mistakes (copy & paste code from another function, for example) and you keep your program _correct_. – Adriano Repetti Jul 06 '15 at 11:31
  • With this in mind then int main(void) is not _incorrenct_ and _bad_. It's **absolutely correct**, it **adheres to C standard** and 1 every 1m times it may help you to avoid simple mistakes. – Adriano Repetti Jul 06 '15 at 11:33
  • 1
    @Lundin Hosted vs. freestanding makes no difference to the signature of `main`. – Potatoswatter Jul 06 '15 at 11:35
  • @Lundin about UB in infinite loop: unfortunately a clarification has been added because specific behavior for this was unspecified then _undefined_ and some compilers will optimize it away (see link in updated answer for one example). – Adriano Repetti Jul 06 '15 at 11:39
  • @Potatoswatter Yes it does. ISO 9899:2011 5.1.2.1 Freestanding environment: `In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.` – Lundin Jul 06 '15 at 12:22
  • @AdrianoRepetti See above quote from the standard. Since it is stated that this is fine and implementation-defined by the standard, `void main (void)` and any other form of main is "standard" in a freestanding environment. Curious how many people that have an opinion about what's "standard" while they haven't actually read the document, or at least not read beyond the hosted environment chapter. – Lundin Jul 06 '15 at 12:24
  • Also you link a C++ post which is irrelevant. C and C++ standards are different in this case. – Lundin Jul 06 '15 at 12:26
  • @Lundin In C and C++ _main function stuff_ are _almost_ identical (unless you push it to the edge to reach the end without returning, re-enter main itself and other _weird_ stuff). That said I have to agree about void main(void), it's completely implementation-defined (and _allowed_ by standard itself)! Thank you for this information! – Adriano Repetti Jul 06 '15 at 14:18
  • @AdrianoRepetti C++ is stricter since it says that a freestanding implementation may or may not define a main function, but if the entry function is named main() it must return `int` etc. (The C++ language has a strong lobby group of PC programmers dictating everything). C++ also don't have the weird "or otherwise in some implementation-defined manner" sentence that C99 and C11 has for hosted implementations. – Lundin Jul 06 '15 at 14:30
  • @Lundin LOL _"...strong lobby of PC programmers..."_. I guess because, I'd be surprised to see C++ on a smal OSless uC! I have to check what they (both standards) say for freestanding environments, I always assumed (wrongly!) they're almost equivalent. – Adriano Repetti Jul 06 '15 at 14:43
  • @Lundin The implementation is equally free to define `void main(void)` in a freestanding or hosted environment. However, the standard specifies an `int` return type, and there's no reason to be nonstandard. The overhead of a return value should be nil even for a tiny platform, because its storage only needs to be allocated if/when `main` returns, which is usually never. This "standard" `void main(void)` business is just your own misconception. – Potatoswatter Jul 06 '15 at 15:30
  • 1
    @Potatoswatter On embedded systems, or indeed in any program, there is always code executed before main() is called. The difference in embedded systems is that the program never terminates. So if you call `int main()` from your reset vector, the calling convention will then dictate that you allocate room for a useless `int` on the stack, which is just wasted memory on a system with memory constaints. – Lundin Jul 07 '15 at 06:11
  • @Potatoswatter As for the standard it specifies what I just quoted. When it says something is implementation-defined, it means that a compiler is free to implement something specific _well-defined_ behavior for that case. As opposed to the standard not mentioning it at all, as in the case of hosted systems. If you don't use the `int main` forms on a hosted system, you may be invoking _undefined behavior_ rather than implementation-defined, which is a big difference. That the standard specifies an `int` return type is _your_ misconception because you are reading the hosted sub-chapter. – Lundin Jul 07 '15 at 06:13
  • @Potatoswatter [Read this](http://stackoverflow.com/questions/5296163/why-is-the-type-of-the-main-function-in-c-and-c-left-to-the-user-to-define/5296593#5296593). – Lundin Jul 07 '15 at 06:15
  • @Lundin (Comment 1) Not really. If the caller allocates storage, the "call" to `main` can simply neglect to do so. The implementation can code it as a `jump` instead of a `call`, for example. If the callee allocates storage, then it's not allocated until the `return` statement executes. – Potatoswatter Jul 07 '15 at 10:30
  • (Comment 2) Again: "The implementation is equally free to define `void main(void)` in a freestanding or hosted environment." In my experience, `int main(void)` is still more common on microcontrollers because it looks more conventional. Of course, it's up to every programmer to RTFM — so this argument is pointless. – Potatoswatter Jul 07 '15 at 10:35
  • @Potatoswatter The hosted implementation is _not_ free to define main as it pleases. Quote the standard if you don't agree. – Lundin Jul 07 '15 at 11:05
  • @Lundin I already did. C11 §5.1.2.2.1: "… or in some other implementation-defined manner." – Potatoswatter Jul 07 '15 at 12:34
1

You haven't made use of FLASH_IS_BUSY, so the preprocessor will not substitute the incorrect syntax.

By the way, be careful with writing while(1); in older C standards (and newer C++ standards), as the behaviour of your program is undefined.

See Is while(1); undefined behavior in C?

Community
  • 1
  • 1
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Sir, how having an infinite loop invokes UB? I understand the _useless_ part, but how it is UB? – Sourav Ghosh Jul 06 '15 at 10:50
  • 2
    It's a well-known technicality. If there was a `printf`, or something similar in the loop body then all would be well. – Bathsheba Jul 06 '15 at 10:51
  • Sorry sir, still I did not get you. Maybe you can point me to some link where I can read more about this (if not asking too much)? Thanks in advance. :-) – Sourav Ghosh Jul 06 '15 at 10:53
  • You're correct. See the linked question. Only since C11 though, and **not** C++11 where it remains undefined. – Bathsheba Jul 06 '15 at 10:54
  • That an empty loop would cause UB sounds like nonsense to me. The compiler isn't allowed to optimize away code if it affects the outcome of the program. Just because a clarification was added in C11, doesn't mean that such loops were undefined behavior until then. There is plenty of uses for empty for-ever loops and they have been used since the dawn of programming. – Lundin Jul 06 '15 at 11:21
  • 1
    @Lundin A function that spins forever instead of returning is not an "outcome" for the C abstract machine, and never was. Try researching first. This site is great for research, and there's a link *right there*. – Potatoswatter Jul 06 '15 at 11:39