The proposed solution follows the guidelines of HT00: It is the caller’s responsibility to pass good data. Nevertheless, we are assuming a software whose requirements demands robustness. That is to say, the software has to keep operating and to crash it is not a valid option. If the software reaches to a an inaccurate result, it should ignore the action which leads to that result.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#if 0
#define DEBUG_ASSERT(ASSERTION) \
{\
if (ASSERTION == false)\
debug_error(__FILE__, __LINE__, #ASSERTION);\
}
#else
#define DEBUG_ASSERT(ASSERTION) if (ASSERTION == true)
#endif
void debug_error(char *file, int ln, char* line)
{
fprintf(stderr, "%s line %d\n'%s'\n",
file, ln, line);
exit(1);
}
/* This functions divides numerator by denominator.
* @precondition Denominator is not zero
* @return result of divide numerator by denominator
*/
static float divide(int numerator, int denominator)
{
return numerator/(float)denominator;
}
int main() {
int numerator, denominator;
float result;
printf("Suppose that we have two numbers as a result of a internal process of data and a zero denominator is");
printf("never Supposeto happen\n");
printf("Input two integers to divide\n");
scanf("%d%d", &numerator, &denominator);
DEBUG_ASSERT(denominator != 0)
{
result = divide(numerator, denominator);
printf("%d/%d = %.2f\n", numerator, denominator, result);
}
return 0;
}
In the first example, a DEGUG_ASSERT macro has been implemented. Turning it on for debug purposes helps us to detect bad input. divide function has a contract by which the denominator can not be zero. Furthermore, every call to divide is wrapped with DEBUG_ASSERT. This way, while debugging we will be able to detect bugs early; in release code, the function is not called with bad input. The action is not accomplished. The macro calls a debug_error to handle it. For release code, a different handle could be implemented. In the example, nothing happens, the function wrapped is not called.
the burden of the responsability is in the caller and if the caller can not assure the validiyt of the data, handle the apropiada respuesta according to the robustneess and consistency requirements.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#if 1
#define DEBUG_ASSERT(ASSERTION) \
{\
if (ASSERTION == false)\
handle_error(__FILE__, __LINE__, #ASSERTION);\
exit(1);\
}
#else
//#define DEBUG_ASSERT(ASSERTION) ( (void) 0)
#define DEBUG_ASSERT(ASSERTION) if (ASSERTION == false)
#endif
typedef enum week_t
{
MONDAY = 0,
TUSDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY,
MAX_WEEK
}week;
static int temperatures[MAX_WEEK] = {12, 13, 19, 11, 21, 20, 22}; /* Cº*/
static int wind_velocity[MAX_WEEK] = {1,3,10,15,19, 8, 7}; /* km/h */
void handle_error(char *file, int ln, char* line)
{
fprintf(stderr, "%s line %d\nfail '%s'\n",
file, ln, line);
exit(1);
}
int get_temperatures(int index)
{
/* Some complex stuff */
return temperatures[index];
}
int get_wind_velocity(int index)
{
return wind_velocity[index];
}
/*
* This functions calculates the thermal sensation of a certain day
* @precondition a day must be withing the range of the days measured
* @day day of the week
*/
float thermal_sensation(week day)
{
return get_temperatures[]
}
/*
*
*/
week get_day()
{
week day;
printf("Input day (number) to obtain thermal sensation (from 1-Monday to 7-Sunday): ");
scanf("%d", &day);
DEBUG_ASSERT(day > 0 && day < MAX_WEEK)
{
day = MONDAY;
}
/* Transform the input into week type*/
return (week)(day-1);
}
float temp_average()
{
int average = 0;
for (int i=0; i<MAX_WEEK; i++)
{
average += get_temperatures(i);
}
return (float)average / (float)MAX_WEEK;
}
int main() {
printf("Temp. average: %2.2f\n", temp_average());
/* Get termal sensation for a certain day*/
printf ("Thermal sensation day %d: %2.2f\n", thermal_sensation(get_day()));
return 0;
}
References
[HT00] Andrew Hunt and David Thomas. 2000. The pragmatic programmer: from journeyman to master. Addison-Wesley Longman Publishing Co., Inc., USA.r