Question about an #if define that is not working as though

I’m using a library to read/write to FRAM non volatile. The library works but I don’t understand how a #define is not doing what I thought.

The library driver defaults to serial outputting Device info via the serial port. What I don’t understand is why I cannot disable this output with a “#define SERIAL_DEBUG = 0” in my program.

The library .h file has (see below for more of the .h file code.

// Enabling debug I2C - comment to disable / normal operations
#ifndef SERIAL_DEBUG
#define SERIAL_DEBUG 1
#endif

I think this says: if “SERIAL_DEBUG” has not been defined then make it =1 . However my program does define “SERIAL_DEBUG” as 0 show this define should not be processed.

Is this an IDE bug I read from a 2011 post? Or am I missing something?

Then in the library .cpp file is the code:

    #if defined(SERIAL_DEBUG) && (SERIAL_DEBUG == 1)

which I just don’t understand why this construction? It seems to work but it seems redundant.

Thanks John.

The below code are just larger excepts of the above, if it helps understand my questionably constructed questions.

the driver can be found here: GitHub - sosandroid/FRAM_MB85RC_I2C: Arduino library for I2C FRAM - Fujitsu MB85RC & Cypress FM24, CY15B · GitHub

/**** first lines of my program ********************************/

#define SERIAL_DEBUG = 0

#include <Wire.h>
#include <math.h>
       
#include <FRAM_MB85RC_I2C.h>

//define a struct of various data types
struct sensorMaxAlltimeure {
	uint16_t CO2;
	uint16_t VOC;
	uint16_t NOx;
	uint16_t PM1;
	uint16_t PM25;
	uint16_t PM10;
};

/**** FRAM_MB85RC_I2C.h ***********************************************/

#ifndef _FRAM_MB85RC_I2C_H_
#define _FRAM_MB85RC_I2C_H_

#if ARDUINO >= 100
 #include <Arduino.h>
#else
 #include <WProgram.h>
#endif

#include <Wire.h>

// Enabling debug I2C - comment to disable / normal operations
#ifndef SERIAL_DEBUG
#define SERIAL_DEBUG 1
#endif

// IDs
//Manufacturers codes
#define FUJITSU_MANUFACT_ID 0x00A
#define CYPRESS_MANUFACT_ID 0x004
#define MANUALMODE_MANUFACT_ID 0xF00
#define MANUALMODE_PRODUCT_ID 0xF00
#define MANUALMODE_DENSITY_ID 0xF00

/**************************************************************************/

#include <stdlib.h>
#include <Wire.h>
#include "FRAM_MB85RC_I2C.h"

first lines of the library source program: FRAM_MB85RC_I2C.cpp

/*========================================================================*/
/*                           PUBLIC FUNCTIONS                             */
/*========================================================================*/

void FRAM_MB85RC_I2C::begin(void) {

	
	
	byte deviceFound = FRAM_MB85RC_I2C::checkDevice();

    #if defined(SERIAL_DEBUG) && (SERIAL_DEBUG == 1)
    		Serial.println(SERIAL_DEBUG);
		if (!Serial) Serial.begin(9600);
		if (Serial){
			Serial.println("FRAM_MB85RC_I2C object created");
			Serial.print("I2C device address 0x");
			Serial.println(i2c_addr, HEX);
			Serial.print("WP pin number ");
			Serial.println(wpPin, DEC);
			Serial.print("Write protect management: ");
			if(MANAGE_WP) {
				Serial.println("true");
			}
			else {
				Serial.println("false");
			}
			if(deviceFound == ERROR_0) {
				Serial.println("Memory Chip initialized");
				FRAM_MB85RC_I2C::deviceIDs2Serial();
			}
			else {
				Serial.println("Memory Chip NOT FOUND");
			}
			Serial.println("...... ...... ......");
		}
    #endif

	return;

Your .ino file is compiled separately from the library's .cpp file.

When your .ino file includes FRAM_MB85RC_I2C.h, your #define SERIAL_DEBUG = 0 is in effect. (By the way, that ought to be #define SERIAL_DEBUG 0.

When the library's .cpp file is compiled and includes FRAM_MB85RC_I2C.h, SERIAL_DEBUG is not defined, and the #ifndef SERIAL_DEBUG block defines SERIAL_DEBUG as 1. So FRAM_MB85RC_I2C.cpp sees SERIAL_DEBUG as 1.

TL;DR: every .cpp (.ino) file is compiled separately and #defines in one .cpp (.ino) file have no visibility or effect on any other .cpp (.ino) file.

In addition to @van_der_decken explanation.

Generally, #define in the .ino file can't affects settings in the library.cpp files. It is not a bug and there is nothing to fix in it.

All the stuff starting with # is the C preprocessor, which is a too-fancy text substitution gizmo, with a few other limited capabilities. For example, build this sketch

#define FOO
#ifdef FOO
  #pragma message "FOO is defined, even if it has no value"
#endif

void setup() {}

void loop() {}

The #define creates a macro. This could just be a simple bit of text, or a macro function, or in this case: nothing. But it is defined, as tested with #ifdef. The condition evaluates to true, so the #pragma is executed, which just prints a message. It will be easier to see if you turn off Show verbose output during compile (so the message in red doesn't just fly by with all that output)

note: '#pragma message: FOO is defined, even if it has no value'
    3 |   #pragma message "FOO is defined, even if it has no value"
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now add a bit

#define FOO
#ifdef FOO
  #pragma message "FOO is defined, even if it has no value"
#endif
#if FOO == 1
  #pragma message "FOO is one"
#else
  #pragma message "FOO is not one"
#endif

void setup() {}

void loop() {}

This will fail to compile:

error: operator '==' has no left operand
    5 | #if FOO == 1
      |         ^~

"No left operand"? The macro is defined, as already shown, but since it is replaced with nothing, the line results in #if == 1, which is what the error is complaining about.

So the construction you asked about is probably an attempt to address this situation. But: it does not work. defined() can be used with #if in a complex expression, but -- reasonably -- works like #ifdef. And as we've seen, "defined as nothing" is still defined.

#if defined(FOO) && FOO == 1

Same error. The preprocessor actually handles this automatically. It only does integer math and comparisons

#if 9 / 3 == 12 / 4

Undefined values automatically have the value zero

#if 9 / 3 == 12 / 4 + SIS_BOOM_BAH

But values that might be defined as nothing/empty require "clever" hacks like

#if (FOO + 0) == 1

which will evaluate to #if ( + 0) == 1 if the macro is empty, and "positive zero equals one" is a valid integer comparison.

BTW, you can define a macro like SERIAL_DEBUG to have a value when all sources are compiled, though a .local.txt config file. Ask if you want more details.

You solved my problem, the “=” sign in a #define seems to nullify that line.

When I removed the = all worked as expected.

I appreciate the other posts, and apologize for my sloppy mistake.

John