【问题标题】:Multiple Source Files in CC中的多个源文件
【发布时间】:2015-01-07 03:19:51
【问题描述】:

我目前正在开发一个实现多个 C 源文件的程序。这是我这样做的第一个项目,并且有很多问题。对于最近的所有问题,我深表歉意,但我真的很感谢您的帮助!

我有一个带有 main 函数的主源文件。在这个主函数中,我有一个调用“高级”函数的操作循环,这些函数本质上是子例程。例如,我有一个名为 ReadInputs() 的函数,它位于“ReadInputs.c”中。出于组织目的,我严格按照这种方式对其进行了分解。

我有几个问题:

我听说将头文件与每个源文件关联是一种很好的做法。正因为如此,我可以有一个名为“ReadInputs.h”的文件,其中包含“ReadInputs.c”中的 ReadInputs() 函数的原型。我的第一个问题是,有必要拥有这么简单的小头文件吗?截至目前,“ReadInputs.h”仅包含一个原型。是否可以将此原型包含在整个头文件中?就我而言,我有一个名为“Definitions.h”的整体头文件,其中包括原型 ReadInputs。

问题2:因为我想在各个源文件之间共享变量,所以我使用如下方法:

我在“main.c”中声明了一个名为 Var 的变量。在“Definitions.h”头文件中,我 extern Var。在所有其他源文件中,我 #include Definitions.h。我相信这将允许变量在全球范围内共享。这是一个正确的假设吗?

对不起,文字墙。任何帮助表示赞赏!

【问题讨论】:

  • 是的,您希望每个源文件有一个标头。不,您确实想要共享变量。全局变量是邪恶的,很少需要。
  • 你能扩展一下吗?例如,我有 3 个函数:ReadInputs()、RunLogic() 和 WriteOutputs()。如果我需要在位于不同源文件中的 ReadInputs() 和 RunLogic() 之间共享数据,我该如何共享?我正在使用我称之为“InputBuffer”的东西,它被写入 ReadInputs() 函数并从 RunLogic() 函数中读取。如何在这两个源文件之间共享数据?
  • 这就是函数参数的用途。你描述它的方式,如果我以你不期望的顺序调用你的函数会发生什么?如果我想写一个我没有从你的 ReadInputs 函数得到的输出怎么办?函数应该很少依赖像全局变量这样的“神奇”外部状态。
  • 是否可以让函数将结构作为输入参数?如果没有,我觉得将 20 个变量传递给一个函数可能会非常混乱。
  • 你可以接收一个结构体或者(更常见的)一个结构体指针,例如void do_stuff(struct awesome *ptr)。但实际上,函数应该是简短的,并且只做好一件事。首先,您应该尽量避免使用 需要 20 个参数的函数。

标签: c


【解决方案1】:
  1. 原型、结构等应在头文件中。这是一种良好的做法,行业遵循此规则。随着代码库的增加,您将添加不同的功能,您的头文件也会增加,所以您不必担心。

  2. 是的,你是对的。

【讨论】:

  • 就在 1 上,我认为问题更多是与每个 C 文件有一个头文件有关,而不是一般的头文件。
【解决方案2】:
  1. 是的,最好为每个源文件使用单独的头文件/.inc 文件。行业遵循规则,每个 .c 文件都有一个 .h 文件或 .inc 文件。函数原型、枚举、宏、结构等应在 .h 或 .inc 文件中声明。

  2. 是的,你正确地使用了应该使用全局变量的方式。 始终在 .c 文件中声明全局变量,避免在任何 .h 文件中声明全局变量,因为在某些编译器中可能会导致多重定义错误。

【讨论】:

  • 你对第一个的回答似乎有点……奇怪。如果我要编写一个包含多个源文件的库(仅出于组织目的),为什么我需要为每个源文件单独的头文件?我不只想要一个包含每个函数原型的头文件,例如“library.h”吗?
  • 您不需要使用 .h 文件。您可以拥有多个 .inc 文件和一个包含所有 .inc 文件的头文件。现在,人们总能感觉到,为什么我需要 .inc 文件来处理 .c 文件,而它可以在单个头文件中完成呢?原因是保留特定于每个文件的特定声明。例如。只有一个文件需要一个结构,您可以避免将其暴露给其他文件。这通常在行业中遵循,但不是强制性的。希望它能回答你的问题。
【解决方案3】:
three files are included below
first the top level makefile
then the bottom level makefile
then an example source file

Note: the makefiles are using 'sed' for
      the creation of the dependency files
      however, the gcc compiler has 
      appropriate parameters that
      can make the operation much simplier

in general, the way to use this is:
-- in the top level directory
   make -f makefile -dDEBUG > make.out
   then examine the file make.out to search for any compile/link errors

Note: I do not know why some lines are being displayed in large/bold font

--- file: makefile.mak
SHELL = /bin/sh


#  note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree


SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      :=  mv

LDFLAGS :=  -L/usr/local/lib -L/usr/lib -L/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -W

#CPPFLAGS += =MD

LIBS    :=  -lssl -ldl -lrt -lz -lc -lm



.PHONY: AllDirectories
# the following statement needs to be edited as 
# subdirectories are added/deleted/re-named
#AllDirectories := \
#    Command_Configuration \
#    Communication \
#    Main_Scheduler \
#    Retrieve_CDS_Log \
#    Retrieve_EventRecorder_Log \
#    Retrieve_GPS \
#    Retrieve_QES_Alarm_Log \
#    Retrieve_QES_RealTime \
#    Write_CDS_Log

AllDirectories :=  \
    Main_Scheduler \
    Communication  \
    Retrieve_GPS   \
    Test_Communication_Dev 



.PHONY: all
#all: $(OBJ) $(AllDirectories)
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak name=Tsk_$d all ); )

all: $(OBJ) $(AllDirectories)
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )



#
# create dependancy files
#
%.d: %.c
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
#clean: $(AllDirectories)
#   # ========== start clean activities ==========
#   rm -f *.o
#   rm -f $(name).map
#   rm -f $(name)
#   rm -f *.d
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end clean activities ==========

clean: $(AllDirectories)
    # ========== start clean activities ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    rm -f ../bin/Tsk_*
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
    # ========== end clean activities ==========



.PHONY: install
#install: $(AllDirectories)
#   # ========== start install activities ==========
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end install activities ==========

install: $(AllDirectories)
    # ========== start install activities ==========
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
    # ========== end install activities ==========



# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

then the makefile (located in the top level directory)
that creates each of the sub directory executables

一次一个,因为它由顶级 makefile 调用

-- file: makefile.bot
SHELL = /bin/sh


BINDIR  :=  /home/user/bin


.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot


#
# macro of all *.c files 
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c 
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)

MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -W

#CPPFLAGS += =MD

#LIBS    :=  -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS    :=   -lssl -ldl -lrt -lz -lc -lm



#
# link the .o files into the executable 
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
    #
    # ======= $(name) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
    # ======= $(name) Link Done ==========
    #



# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
    #
    # ======= $(name) Copy Start =========
    sudo $(CP) $(name) $(BINDIR)/.
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



# 
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
clean: 
    # ========== CLEANING UP ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    # ========== DONE ==========



.PHONY: install
install: all

# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

and finally, a typical file, showing the many local and system headers used
note: although the usage was trivial in this file, 
      the doxygen documentation utility
      was used in the process of automatic document creation

这是使用“@”行的地方。

-- file: Main_Scheduler.c
/**
    @file   Main_Scheduler.c
    @brief  contains functions to control 'deleted'
    @author Richard Williams
    @date   June 27, 2012
*/


/*  SIRT issues applied to this file:
    SIRT issue ### -

*/


/* *************** Included files ************************************* */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>    // for system() and itoa() utilities
#include <stdarg.h>    // for va_list(), etc
#include <string.h>    // string handling utilities
#include <semaphore.h> // semaphores handling utilities

#include <fcntl.h>     // symbolic definitions for flags bits
#include <sys/types.h> // contains definitions of data types used in system calls
#include <sys/socket.h>// type definitions (I.E. struct sockaddr_in)
#include <sys/stat.h>  // symbolic definitions for permission bits and open()
#include <sys/ipc.h>   // ipc interface utilities

#include <sys/shm.h>   // shared memory utilities
#include <arpa/inet.h> // defines INADDR_ANY, etc

#include <errno.h>     // for accessing errno and related functions
#include <stdbool.h>   // define true, false, bool
#include <time.h>      // prototypes for time() and related functions


    // contains common data type definitions
#include "../GOT4_Types.h"

    // contains data definitions for ON and OFF
#include "../CdsDefines.h"

    // contains prototypes for Interprocess Communication
#include "../Common_Interprocess_Communication.h"

    // contains prototypes for UDP utility functions
#include "../Common_UDP_Utilities.h"

    // contains prototypes and enums for configuration operations
#include "../CommonConfiguration.h"

    // contains prototypes for writing to CDS Log file
#include "../CommonWriteCdsLog.h"

    // contains prototypes for handling stderr files
#include "../CommonDateFunctions.h"

    // contains prototypes and enums for watchdog operations
#include "Main_Scheduler_Watchdog.h"

    // contains prototypes and enums for command operations
#include "Main_Scheduler_Command.h"

    //contains prototypes for globally visible functions and data types in this file
#include "Main_Scheduler.h"



/* *************** File static functions ****************************** */
static enum enumReturnStatus Main_Scheduler_StartTask( INT32 taskSelector );
static enum enumReturnStatus Main_Scheduler_StopTask ( INT32 taskSelector );

static enum enumReturnStatus Main_Scheduler_Task__Initialize( void );
static enum enumReturnStatus Main_Scheduler_Config__Initialize( BOOL bFirstTime );



#define dMAX_IPC_PAYLOAD ( 256 )
#define dMAX_SYSTEM_BUF_LENGTH ( 256 )

/* *************** Global Variables *********************************** */



/* *************** File Static Variables ****************************** */
static BOOL   ActiveTaskTable[ eMaxTasks ] = { FALSE };


// used to format the payload of messages to write to IPC
//static char   inITC_payload[ dMAX_IPC_PAYLOAD ];
static char   outITC_payload[ dMAX_IPC_PAYLOAD ];

// used for executing commands in shell
static char   systemCommand[dMAX_SYSTEM_BUF_LENGTH] = {0x00};


// used to enable kicking the hardware watchdog
static BOOL   flgWatchdogKick = TRUE;



/* *************** Code *********************************************** */



/**
  @fn INT32 main(INT32 argc, char *argv[])
  @brief -
  @param [in] argc -
  @param [in] argv -
  @return INT32 -

  :

 */
INT32 main( INT32 argc __attribute__ ((unused)), char* argv[] )
{
    enum enumReturnStatus returnStatus;

    INT32  taskSelector; // loop counter
    INT32  CommandValue; // command to send to sub task

    struct structWriteIPC WriteIPC;

    struct timespec       timeout;  // timeout for interprocess communication call
    unsigned              priority; // message priority for sending messages, 5 is low, 10 is high

    char  *pBaseName =    gnu_basename( argv[ 0 ]); // get name of this file

    remove_all_IPC();  // Only done from Main Scheduler, clears out all external (OS) interprocess buffers

    Initialize_IPC();
    itc_payload_size_init();

    set_TaskSelector( eTask_Main_Scheduler );

    set_pTask_NameString( eTask_Main_Scheduler, pBaseName );

    // select initial file to receive stderr messages
    CommonDateFunctions_stderr( pBaseName );

    // initialize the logging subsystem, indicating not owner of resource
    CommonWriteCdsLog__Initialize();

    if( atexit( release_CommonConfiguration ) )
    { // then setting exit function failed

        CommonWriteCdsLog( eLL_Critical,
            get_pFormatString( eFormat_CFFL_string_string ),
            __FILE__, __LINE__,
            "LibFunc:atexit()",
            strerror(errno) );

        system( "sync; sync;" );
        exit( EXIT_FAILURE);
    }


    /*
     * ***************************************************************
     * implied else (atexit() successful)
     *****************************************************************
     */


    // read .config file and initialize database
    Main_Scheduler_Config__Initialize( TRUE ); // true=first time

    returnStatus = Main_Scheduler_Task__Initialize();


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "Entering main execution loop" );


    /*
    *********************************************************************
    * main operating loop starts here
    * *******************************************************************
    */


    flgWatchdogKick = true;
    while( flgWatchdogKick )
    {
        // step to next stderr file at midnight, otherwise do nothing
        CommonDateFunctions_stderr( pBaseName );

        // 11 kick the CPU watchdog
        Main_Scheduler_wd_kick();



        // 12) kick the external watchdog
        //todo:

        for( taskSelector=1; // step by main_scheduler task=(0)
             taskSelector<eMaxTasks ;
             taskSelector++ )
        {

            if( !ActiveTaskTable[  taskSelector ] )
            { // then selected task not configured to run

                continue; // step to next itteration of inner loop
            }


            /*
             *********************************************************************
             * implied else, task-of-interest ready to run
             * *******************************************************************
             */


            // throttle execution rate of sub tasks
            step_Interval_counter( taskSelector );

            if( is_Interval_expired( taskSelector) )
            { // then, kick related task

                reset_Interval_counter( taskSelector );

                // note: get_Task_command() handles all errors
                CommandValue = get_Task_command( taskSelector );


                if( eTask_Retrieve_GPS == taskSelector )
                {

                    CommandValue = eTaskCommand_GetGPSreport; // periodic event
                }


fprintf( stdout,"DEBUG:File:%s\n\t--> ATTEMPTING TO KICK cmd#:%d TASK# %d\n", __FILE__, CommandValue, taskSelector );
fflush( stdout );

fprintf( stdout,"DEBUG:File:%s\n\t--> task:%d, command;%d\n\n", __FILE__, taskSelector, CommandValue );
fflush( stdout );

                memset( outITC_payload, 0x00, sizeof(outITC_payload) );
                ((struct structITC_Command*)outITC_payload)->ITC_Receiver = taskSelector;
                ((struct structITC_Command*)outITC_payload)->ITC_Command  = CommandValue;

                WriteIPC.TaskSelector    = taskSelector;
                WriteIPC.ITC_MsgType     = eITC_MsgType_Command;
                WriteIPC.ITC_PayLoadSize = 2*sizeof(INT32);
                WriteIPC.pITC_Payload    = outITC_payload;


fprintf( stdout,"DEBUG:File:%s\n\t--> calling write_ITC_Record_To_IPC() with taskSelector:%d\n\n", __FILE__, taskSelector );
fflush( stdout );


                clock_gettime(CLOCK_REALTIME, &timeout);   // gets current time
                timeout.tv_sec +=  1;                      // adds one second to current time for timeout
                priority        = 10;
                returnStatus    = write_ITC_Record_To_IPC( &WriteIPC, &timeout, priority );

fprintf( stdout,"DEBUG:File:%s\n\t--> returned from write_ITC_Record_To_IPC()\n\n", __FILE__ );
fflush(  stdout );

                if( eRS_Success == returnStatus )
                { // then. write successful

fprintf( stdout,"DEBUG:File:%s\n\t--> SUCCESFULLY SENT MSG TO TASK#%d\n", __FILE__, taskSelector );
fflush(  stdout );

                    // overwrite command so not executed again.
                    set_Task_command( taskSelector, eTaskCommand_DoNothing );
                }
else
{
fprintf( stdout,"DEBUG:File:%s\n\t--> FAILED TO SEND MSG TO TASK#%d   error is:%d\n", __FILE__, taskSelector, returnStatus );
fflush(  stdout );
}
            } // endif( is interval expired )
        } // end for( each task )

        // wait a second before going through the above again
        sleep(1);


        // 16) get any new commands
        // rkw: comment until ready to receive commands from CommandConfiguration task
        // Main_Scheduler_Command();
    } // end while( flgWatchdogKick )


    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_Exiting_Status ),
        __func__, __FILE__, EXIT_SUCCESS );

    return( EXIT_SUCCESS );
} // end main()



static enum enumReturnStatus Main_Scheduler_StartTask( INT32 taskSelector )
{
    char *pTask_NameString;
    int   systemReturn;


    if( is_taskSelector_Valid( taskSelector) )
    {

        // note: task_nameString is setup during call to Main_Scheduler_Config__Initialize()
        pTask_NameString = get_pTask_NameString( taskSelector );

        if( NULL != pTask_NameString )
        { // then get_pTask_NameString successful

            memset( systemCommand, 0x00, sizeof(systemCommand) );

            // set the command string
            // set to run in background so will get execution back
            sprintf( systemCommand, "%sTsk_%s &", dEXECUTION_DIR, pTask_NameString );

            // pass tracking message to CDS log file
            CommonWriteCdsLog( eLL_Critical, // Critical to assure will be written to log file
                get_pFormatString( eFormat_CFFL_string ),
                __FILE__, __LINE__,
                systemCommand );

fprintf( stdout,"DEBUG:File:%s\n\t--> starting subsytem: %s\n", __FILE__, systemCommand );
fflush( stdout );

            // run the command ( which starts the task )
            systemReturn = system( systemCommand );

            if (( 0 != systemReturn ) )
            {
                CommonWriteCdsLog( eLL_Critical,
                    get_pFormatString( eFormat_CFFL_digit_string ),
                    __FILE__, __LINE__, systemReturn,
                    "system() call failed." );

                system( "killall Tsk*" );
                system("sync;sync;");
                exit( EXIT_FAILURE );
            }

            return( eRS_Success ); // indicate operation successful
        }

        //else
        //{ // else, get_pTask_NameString() failed
          // which means the task is not configured in the .config file

        //    CommonWriteCdsLog( eLL_Error,
        //        get_pFormatString( eFormat_EFFL_digit_string ),
        //        __FILE__, __LINE__,
        //        taskSelector,
        //        "=taskSelector: Function:get_pTask_NameString() failed" );
        //} // endif( got task name string )
    }

    else
    { // else, bad parameter

        CommonWriteCdsLog( eLL_Error,
            get_pFormatString( eFormat_EFFL_digit_string ),
            __FILE__, __LINE__,
            taskSelector,
            "=taskSelector: Parameter out of range" );
    }

    return( eRS_Failure ); // indicate error occurred
} // end Main_Scheduler_StartTask()



static enum enumReturnStatus Main_Scheduler_StopTask ( INT32 taskSelector )
{
    char systemCommand[ 256 ];
    char *pTask_NameString;



    if( is_taskSelector_Valid( taskSelector ) )
    {
        memset( systemCommand, 0x00, sizeof(systemCommand) );
        pTask_NameString = get_pTask_NameString( taskSelector );

        if( NULL != pTask_NameString )
        { // then, get_pTask_NameString successful

            sprintf( systemCommand, "killall %sTsk_%s", dEXECUTION_DIR, pTask_NameString );

            // pass tracking message to CDS log file
            CommonWriteCdsLog( eLL_Critical,
                get_pFormatString( eFormat_CFFL_string ),
                __FILE__, __LINE__,
                systemCommand );

            // run the command, which kills the task
            system( systemCommand );

            return( eRS_Success ); // indicate success
        }
    }

    else
    { // else, bad parameter

        CommonWriteCdsLog( eLL_Error,
            get_pFormatString( eFormat_EFFL_digit_string ),
            __FILE__, __LINE__,
            taskSelector,
            "=taskSelector: Parameter out of range" );
    }


    return( eRS_Failure ); // indicate problem occurred
} // end Main_Scheduler_StopTask()



static enum enumReturnStatus Main_Scheduler_Config__Initialize( BOOL bFirstTime )
{
    enum enumReturnStatus returnStatus = eRS_Success;


    // Note: check for first time avoids trying to 'free() un-initialized char pointers
    if( !bFirstTime )
    {
        release_CommonConfiguration();
    }

    clear_CommonConfiguration();

    acquire_CommonConfiguration( eDivision_Main_Scheduler );

    return( returnStatus );
} // end Main_Scheduler_Config__Initialize()



static enum enumReturnStatus Main_Scheduler_Task__Initialize( void )
{
    enum enumReturnStatus returnStatus = eRS_Success;

    INT32 taskSelector;



    // 2) reset the IOC card
    memset( systemCommand, 0x00, sizeof(systemCommand) );
    strcat( systemCommand, "/usr/bin/diag_client -s 172.20.100.17:23 'reset'" );
    //rkw for testing system( systemCommand );



    // 3) reset the DIO card
    memset( systemCommand, 0x00, sizeof(systemCommand) );
    strcat( systemCommand, "/usr/bin/diag_client -s 172.20.100.18:23 'reset'" );
    //rkw for testing system( systemCommand );



    /*
    *********************************************************************
    * start task execution
    * *******************************************************************
    */


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "kill any running Task" );

    for( taskSelector=1; // task 0 is Main_Scheduler (I.E. this task)
         eMaxTasks > taskSelector;
         taskSelector++ )
    {
        Main_Scheduler_StopTask( taskSelector );
    }


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "Entered: Start Task Execution Loop" );

    for( taskSelector=1; // task 0 is Main_Scheduler (I.E. this task)
         eMaxTasks > taskSelector;
         taskSelector++ )
    {

        returnStatus = Main_Scheduler_StartTask( taskSelector );

        if( eRS_Success == returnStatus )
        {
            ActiveTaskTable[ taskSelector ] = TRUE;
        }

        else
        { // else, task not configured

            ActiveTaskTable[ taskSelector ] = FALSE;
        }
    } // end for( each possible task )




    /*
    *********************************************************************
    * initialization loop
    * *******************************************************************
    */


    // 8) set task initializer command for each task

    for( taskSelector=1; // step by Main_Scheduler task=0
         taskSelector>=eMaxTasks;
         taskSelector++ );
    {

        set_Task_command( taskSelector, eTaskCommand_Initialize );
    } // end for( each task to initialize )



    /*
    *********************************************************************
    * initialze CPU card and external watchdog operations
    * *******************************************************************
    */


    // 9) initialize the CPU watchdog
    Main_Scheduler_wd_init();
    Main_Scheduler_wd_enable();

    // 9.1 set kickWatchdog flag to indicate watchdog is to be kicked
    flgWatchdogKick = TRUE;


    // 10) initialize throttle timers
    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "resetting all timers" );

    for( taskSelector=0;
         taskSelector<eMaxTasks ;
         taskSelector++ )
    {

        reset_Interval_counter( taskSelector );
    }

    return( returnStatus );
} // end Main_Scheduler_Task__Initialize()



/* ******************************************************************** **
** End of source file: Main_Scheduler.c
** ******************************************************************** */


I know the above examples contain the information that you need
for your project.  
But it may be a bit difficult  to decyper without knowing 
the makefile syntax and builtin calls

【讨论】:

  • 上面的示例代码应该为 OP 提供编译/链接由多个文件组成的一个可执行文件所需的所有信息。
【解决方案4】:

对于您的第一个问题,是的,这种情况经常发生。

例如,考虑一组实现平衡树的文件,其中包含用于插入、删除查找等的不同 C 源文件。这通常是为了更好的构建过程,例如,如果这是您唯一更改的内容,则只需重新编译 insert 文件。

但是,您希望代码的 用户 只需要包含一个 btree.h,因此您只需将所有函数原型(和其他内容)集中到其中。

所以你最终会得到类似的东西:

btree.h            - public stuff
btree_priv.h       - private stuff
btreeInsert.c      - individual functions
btreeDelete.c
btreeFind.c
btreeRebalance.c
btreeIterate.c

btree_priv.h 文件包含足够的信息,超出用户标头 btree.h,以允许各自源文件中的各个函数相互了解以及“隐藏”数据结构。

然后,您通常会将所有已编译的“单个函数”对象文件打包到一个库中,然后分发该库和公共头文件。

第二个问题也是如此,但有一点需要注意。 extern 将显式声明该变量,以便其他翻译单元(源文件)知道它。但它是(例如)在文件级别将其声明为非静态的行为,这将使其在链接时对您链接的所有文件可见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    相关资源
    最近更新 更多