Home Database Mysql Tutorial Accessing static Data and Functions in Legacy C

Accessing static Data and Functions in Legacy C

Jun 07, 2016 pm 03:44 PM
and data static

http://www.renaissancesoftware.net/blog/archives/450 It’s a new year; last year was a leap year; so the quadrennial reports of leap year bugs are coming in. Apologies are in the press from Apple, TomTom, and Microsoft. Trains we stopped f

http://www.renaissancesoftware.net/blog/archives/450

It’s a new year; last year was a leap year; so the quadrennial reports of leap year bugs are coming in. Apologies are in the press from Apple, TomTom, and Microsoft. Trains we stopped from running in China. Somehow calling them glitches seems to make it someone else’s fault, something out of their control. How long have leap years been around? Julius Caesar introduced Leap Years in the Roman empire over 2000 years ago. The Gregorian calendar has been around since 1682. This is not a new idea, or a new bug.

I’m going to try to take one excuse away from the programmers that create these bugs by answering a question that comes up all the time, “How do I test static functions in my C code?”

In code developed using TDD, static functions are tested indirectly through the public interface. As I mentioned in a this article TDD is a code rot radar. It helps you see design problems. Needing direct access to hidden functions and data in C is a sign of code rot. It is time to refactor.

But what about existing legacy code that has statics? It is probably way past the time for idealism and time for some pragmatism. In this article and the next, we’ll look at how to get your code untouched into the test harness and access those pesky <span>static </span>variables and functions.

If you don’t mind touching your code, you could change all mentions of static to STATIC. Then using the preprocessor, STATIC can he set to static during production and to nothing for test, making the names globally accessible. In gcc you would use these command line options

  • For production builds use -dSTATIC=static
  • For unit test builds use -dSTATIC

Let’s look at two options that, at least for access to statics, you will not have to touch your code to get it under test. First is <span>#include</span>-ing your .c in the test file. In the next article we’ll build a test adapter .c that give access to the hidden parts.

We are going to revisit code that is similar to the original code responsible for the Zune Bug. I rewrote the code to avoid attracting any lawyers but it is structured similarly to the original Zune driver, complete with static data and functions that must be correct for the function to work.

The header file provides a data structure and initialization function for figuring out the information about the date. Here is the header:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

typedef struct Date

{

    int daysSince1980;

    int year;

    int dayOfYear;

    int month;

    int dayOfMonth;

    int dayOfWeek;

} Date;

  

void Date_Init(Date *, int daysSince1980);

  

enum {

    SUN = 0, MON, TUE, WED, THU, FRI, SAT

};

  

enum {

    JAN = 0, FEB, MAR, APR, MAY, JUN,

    JUL, AUG, SEP, OCT, NOV, DEC

};

Copy after login

Date_Init populates the Date instance passed in. Ignoring the fact that I can probably fully test this by rigging the daysSince1980, and inspecting the contents of the resultingDate structure, we are going to see how we can directly test the hidden functions and data.

Date_Init has three hidden helper functions.

1

2

3

4

5

6

7

void Date_Init(Date* date, int daysSince1980)

{

     date->daysSince1980 = daysSince1980;

     FirstSetYearAndDayOfYear(date);

     ThenSetMonthAndDayOfMonth(date);

     FinallySetDayOfWeek(date);

}

Copy after login

Date_Init is the tip of the iceberg. All the interesting stuff is happening in the hidden data and functions:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

#include "Date.h"

#include <stdbool.h>

  

enum

{

    STARTING_YEAR = 1980, STARTING_WEEKDAY = TUE

};

  

static const int nonLeapYearDaysPerMonth[12] =

{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

  

static const int leapYearDaysPerMonth[12] =

{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

  

static bool IsLeapYear(int year)

{

    if (year % 400 == 0)

        return true;

    if (year % 100 == 0)

        return false;

    if (year % 4 == 0)

        return true;

    return false;

}

  

static int GetDaysInYear(int year)

{

    if (IsLeapYear(year))

        return 366;

    else

        return 365;

}

  

static void FirstSetYearAndDayOfYear(Date * date)

{

    int days = date->daysSince1980;

    int year = STARTING_YEAR;

    int daysInYear = GetDaysInYear(year);

  

    while (days > daysInYear)

    {

        year++;

        days -= daysInYear;

        daysInYear = GetDaysInYear(year);

    }

  

    date->dayOfYear = days;

    date->year = year;

}

  

static void ThenSetMonthAndDayOfMonth(Date * date)

{

    int month = 0;

    int days = date->dayOfYear;

    const int * daysPerMonth = nonLeapYearDaysPerMonth;

    if (IsLeapYear(date->year))

        daysPerMonth = leapYearDaysPerMonth;

  

    while (days > daysPerMonth[month])

    {

        days -= daysPerMonth[month];

        month++;

    }

    date->month = month + 1;

    date->dayOfMonth = days;

}

  

static void FinallySetDayOfWeek(Date * date)

{

     date->dayOfWeek =((date->daysSince1980-1)+STARTING_WEEKDAY)%7;

}

  

void Date_Init(Date* date, int daysSince1980)

{

     date->daysSince1980 = daysSince1980;

     FirstSetYearAndDayOfYear(date);

     ThenSetMonthAndDayOfMonth(date);

     FinallySetDayOfWeek(date);

}</stdbool.h>

Copy after login

Let’s say you want to check the days per month vectors. You might want to write a test to check the months against the handy poem we use here in the US: Thirty days, has September, April, June and November; all the rest have thirty-one, except for February. It has 28 except in leap year it has 29.

If you started by writing this test…

1

2

3

4

TEST(Date, sept_has_30_days)

{

    LONGS_EQUAL(30, nonLeapYearDaysPerMonth[SEP]);

}

Copy after login

… you get this error:

1

DateTest.cpp:41: error: 'nonLeapYearDaysPerMonth' was not declared in this scope

Copy after login

Let’s get access to the hidden statics in the test case by including Date.c instead ofDate.h in DateTest.cpp. The full test case file looks like this now:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#include "CppUTest/TestHarness.h"

  

extern "C"

{

#include "Date.c"

}

  

TEST_GROUP(Date)

{

};

  

TEST(Date, sept_has_30_days)

{

    LONGS_EQUAL(30, nonLeapYearDaysPerMonth[SEP]);

}

Copy after login

With a little refactoring days per month vectors can be checked like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

#include "CppUTest/TestHarness.h"

  

extern "C"

{

#include "Date.c"

}

  

TEST_GROUP(Date)

{

    const int * daysPerYearVector;

  

    void setup()

    {

        daysPerYearVector = nonLeapYearDaysPerMonth;

    }

  

    void itsLeapYear()

    {

        daysPerYearVector = leapYearDaysPerMonth;

    }

  

    void CheckNumberOfDaysPerMonth(int month, int days)

    {

        LONGS_EQUAL(days, daysPerYearVector[month]);

    }

  

    void ThirtyDaysHasSeptEtc()

    {

        CheckNumberOfDaysPerMonth(SEP, 30);

        CheckNumberOfDaysPerMonth(APR, 30);

        CheckNumberOfDaysPerMonth(JUN, 30);

        CheckNumberOfDaysPerMonth(NOV, 30);

  

        CheckNumberOfDaysPerMonth(OCT, 31);

        CheckNumberOfDaysPerMonth(DEC, 31);

        CheckNumberOfDaysPerMonth(JAN, 31);

        CheckNumberOfDaysPerMonth(MAR, 31);

        CheckNumberOfDaysPerMonth(MAY, 31);

        CheckNumberOfDaysPerMonth(JUL, 31);

        CheckNumberOfDaysPerMonth(AUG, 31);

    }

  

    void ExceptFebruaryHas(int days)

    {

      CheckNumberOfDaysPerMonth(FEB, days);

    }

};

  

TEST(Date, non_leap_year_day_per_month_table)

{

    ThirtyDaysHasSeptEtc();

    ExceptFebruaryHas(28);

}

  

TEST(Date, leap_year_day_per_month_table)

{

    itsLeapYear();

    ThirtyDaysHasSeptEtc();

    ExceptFebruaryHas(28);

}

Copy after login

You have access to all the hidden stuff, so you can write the test for the static functions:

IsLeapYear()GetDaysInYear()FirstSetYearAndDayOfYear(),ThenSetMonthAndDayOfMonth(), and FinallySetDayOfWeek().

If Date been an abstract data type, with its data structure hidden in the .c file, the tests would all have access to structure members hidden from the rest of the world.

There is a downside to this approach, which probably does not matter in this case, but could in others. You can only have one test file that can include a given .c file. In the next article we’ll solve that problem.

Have you heard of any interesting leap year bugs? Did you prevent your own?

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What is the function and usage of static in C language What is the function and usage of static in C language Jan 31, 2024 pm 01:59 PM

The role and usage of static in C language: 1. Variable scope; 2. Life cycle; 3. Internal function; 4. Modify global variables; 5. Modify function; 6. Other uses; Detailed introduction: 1. Variable scope, when If there is the static keyword before a variable, then the scope of the variable is limited to the file in which it is declared. In other words, the variable is a "file-level scope", which is very useful for preventing the "duplicate definition" problem of variables; 2. Life cycle, static variables are initialized once when the program starts executing, and destroyed when the program ends, etc.

What data is in the data folder? What data is in the data folder? May 05, 2023 pm 04:30 PM

The data folder contains system and program data, such as software settings and installation packages. Each folder in the Data folder represents a different type of data storage folder, regardless of whether the Data file refers to the file name Data or the extension. Named data, they are all data files customized by the system or program. Data is a backup file for data storage. Generally, it can be opened with meidaplayer, notepad or word.

How to use static, this, super, and final in Java How to use static, this, super, and final in Java Apr 18, 2023 pm 03:40 PM

1. static Please look at the following program first: publicclassHello{publicstaticvoidmain(String[]args){//(1)System.out.println("Hello, world!");//(2)}} Have seen this Segment programs are familiar to most people who have studied Java. Even if you have not learned Java but have learned other high-level languages, such as C, you should be able to understand the meaning of this code. It simply outputs "Hello, world" and has no other use. However, it shows the main purpose of the static keyword.

Practical application scenarios and usage skills of the static keyword in C language Practical application scenarios and usage skills of the static keyword in C language Feb 21, 2024 pm 07:21 PM

Practical application scenarios and usage skills of the static keyword in C language 1. Overview static is a keyword in C language, used to modify variables and functions. Its function is to change its life cycle and visibility during program running, making variables and functions static. This article will introduce the actual application scenarios and usage techniques of the static keyword, and illustrate it through specific code examples. 2. Static variables extend the life cycle of variables. Using the static keyword to modify local variables can extend their life cycle.

What to do if mysql load data is garbled? What to do if mysql load data is garbled? Feb 16, 2023 am 10:37 AM

The solution to the garbled mysql load data: 1. Find the SQL statement with garbled characters; 2. Modify the statement to "LOAD DATA LOCAL INFILE "employee.txt" INTO TABLE EMPLOYEE character set utf8;".

How to use Java modifiers abstract, static and final How to use Java modifiers abstract, static and final Apr 26, 2023 am 09:46 AM

Modifier abstract (abstract) 1. Abstract can modify a class (1) The class modified by abstract is called an abstract class (2) Syntax: abstractclass class name {} (3) Features: Abstract classes cannot create objects separately, but they can be declared Reference the abstract class name reference name; (4) Abstract classes can define member variables and member methods (5) Abstract classes have constructors. When used to create subclass objects, jvm creates a parent class object by default; abstract constructor methods apply Applied when jvm creates parent class object. 2. Abstract can modify methods (1) The method modified by asbtract is called an abstract method (2) Syntax: access modifier abstract return value

The role of static The role of static Jan 24, 2024 pm 04:08 PM

The functions of static: 1. Variables; 2. Methods; 3. Classes; 4. Other uses; 5. Multi-threaded environment; 6. Performance optimization; 7. Singleton mode; 8. Constants; 9. Local variables; 10. Memory Layout optimization; 11. Avoid repeated initialization; 12. Use in functions. Detailed introduction: 1. Variables, static variables. When a variable is declared as static, it belongs to the class level, not the instance level, which means that no matter how many objects are created, only one static variable exists, and all objects share this Static variables and so on.

What are the differences between xdata and data What are the differences between xdata and data Dec 11, 2023 am 11:30 AM

The differences are: 1. xdata usually refers to independent variables, while data refers to the entire data set; 2. xdata is mainly used to establish data analysis models, while data is used for data analysis and statistics; 3. xdata is usually used for regression Analysis, variance analysis, predictive modeling, data can be analyzed using various statistical methods; 4. xdata usually requires data preprocessing, and data can contain complete original data.

See all articles