在C编译器#define指令中是否有与awk sprintf等效的指令

ruoxqz4g  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(99)

对于上下文,我试图做一些简单的本地化,作为进入“海洋”的第一步,有限的语言选项。我想更“包容”,而不仅仅是限于逐项列出该类型的所有示例(bash环境变量的值有3个选项 LANGUAGE*)

#define SPANISH 'es_MX:es'
#define FRENCH  'fr_CA:fr'
#define ENGLISH 'en_CA:en'

在awk,我可以做

MYLANG = sprintf("%2s", LANG)

我想做一些简单的事情,所以我可以做

//awk syntax for sprintf
#define   MYLANG   {simple}

仅获取字符串LANG的前2个字符。
有什么我可以用的吗?
完整的工作脚本,除了不能访问环境变量LANGUAGE外,所有行为都符合预期,如下所示:

#include <langinfo.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

#define SPANISH 'es'
#define FRENCH  'fr'
#define ENGLISH 'en'

#ifndef LANGUAGE
#include "CIMIfrecN_MessagesTable_fr.h"
#else

#define MYLANG LANGUAGE[0],LANGUAGE[1]      // not valid

#if MYLANG == SPANISH
//#include "_cimifrecn_messagestable_es_h"
#include "CIMIfrecN_MessagesTable_es.h"
#elif MYLANG == FRENCH
//#include "_cimifrecn_messagestable_fr_h"
#include "CIMIfrecN_MessagesTable_fr.h"
#else
//#include "_cimifrecn_messagestable_en_h"
#include "CIMIfrecN_MessagesTable_en.h"
#endif
#endif
//==================================================================================================
//  START OF MAIN PROGRAM
//==================================================================================================

int main(){

    char yellowON[12]="\e[93;1m" ;
    char yellowOFF[12]="\e[0m" ;

    char redON[12]="\e[91;1m" ;
    char redOFF[12]="\e[0m" ;

    char blueON[12]="\e[94;1m" ;
    char blueOFF[12]="\e[0m" ;

    char ThisLOCALE[30] ;

    sprintf( ThisLOCALE, "%s", setlocale(LC_ALL, "") ) ;
    printf("\n\t %s\n\n", ThisLOCALE ) ;

    printf("\n  == %s%s%s ==\n", blueON, ScenarioSetUp, blueOFF ) ;

    return 0;
}

输出显示如下:

  • 这表明使用两个对LANGUAGE的单位置引用的建议方法不起作用 *。:-(

我是<Addendum 1>说
因此,我尝试了该脚本的修订版本,在那里我确实与LANGUAGE变量的 full value 进行了比较,认为它证明了在预处理期间可以访问它。不幸的是,我没有意识到我有英语作为默认的后备情况,所以我的结论是不正确的。我得到了一个假阳性。:-(

...(deleted)...

我是<Addendum 2>说
我再次修改了我的程序,为特定的值匹配设置了English,并添加了特定的字符串来识别遇到了哪些无效条件:

#include <langinfo.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

#define SPANISH 'es_MX:es'      // Format reported by bash environment variable LANGUAGE
#define FRENCH  'fr_CA:fr'
#define ENGLISH 'en_CA:en'
//#define SPANISH 'es'
//#define FRENCH  'fr'
//#define ENGLISH 'en'

//#define TESTOR LANGUAGE[0],LANGUAGE[1]    // not valid
#define TESTOR LANGUAGE

//#ifndef LANG
#ifndef TESTOR
    char ScenarioSetUp[30] = "TESTOR was not defined" ;
//#include "_cimifrecn_messagestable_es_h"
#include "CIMIfrecN_MessagesTable_es.h"
#else

#if TESTOR == NULL
    char ScenarioSetUp[50] = "LANGUAGE was not obtained from the environment" ;
#elif TESTOR == SPANISH

//#include "_cimifrecn_messagestable_es_h"
#include "CIMIfrecN_MessagesTable_es.h"
#elif TESTOR == ENGLISH
//#include "_cimifrecn_messagestable_en_h"
#include "CIMIfrecN_MessagesTable_en.h"
#else
//#include "_cimifrecn_messagestable_fr_h"
#include "CIMIfrecN_MessagesTable_fr.h"
#endif

#endif

//==================================================================================================
//  START OF MAIN PROGRAM
//==================================================================================================

//int setProgramLOCALE(){
int main(){

    char yellowON[12]="\e[93;1m" ;
    char yellowOFF[12]="\e[0m" ;

    char redON[12]="\e[91;1m" ;
    char redOFF[12]="\e[0m" ;

    char blueON[12]="\e[94;1m" ;
    char blueOFF[12]="\e[0m" ;

    char ThisLOCALE[30] ;

    sprintf( ThisLOCALE, "%s", setlocale(LC_ALL, "") ) ;
    printf("\n\t %s\n\n", ThisLOCALE ) ;

    printf("\n  == %s%s%s ==\n", blueON, ScenarioSetUp, blueOFF ) ;

    return 0;
}

这一次,它明确地显示了在编译器指令的TESTOR赋值中检测LANGUAGE失败,正如报告的消息所示:

因此,我仍然在寻找一种方法,在编译器指令中获取LANGUAGE。:-(
请帮帮我

示例包含文件:

//==================================================================================================
//  FILE:   CIMIfrecN_MessagesTable_fr.h
//  Header initializing context-based messages for the program
//==================================================================================================

#ifndef _cimifrecn_messagestable_fr_h
#define _cimifrecn_messagestable_fr_h

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>

    char ScenarioSetUp[91]                = "configuration du scénario" ;
    char EnterDesiredFrequency[91]        = "Veuillez entrer la fréquence désirée" ;
    char DesiredFrequency[91]             = "Fréquence désirée" ;
    char NumberLevelsImplied[91]          = "Nombre de niveaux impliqués" ;
    char NumberStrutsRequired[91]         = "Nombre de poutres nécessaires" ;
    char EvaluationPointRelevance[91]     = "Évaluation des point du grillage pour identifier leur pertinence" ;
    char Considering[91]                  = "Examinons" ;
    char Horizontals[91]                  = "Horizontales" ;
    char NoneMetCriteria[91]              = "(aucunes comblait les critères)" ;
    char Diagnonals[91]                   = "Diagonales" ;
    char VerticesMinimalSet[91]           = "Intersections identifiées pour un ensemble minimal contraignant entièrement la grille" ;
    char ThereAre[91]                     = "Il y a" ;
    char Vertices[91]                     = "Intersections" ;
    char VerteIndexMatrix[91]             = "Matrice des indices pour Intersections" ;
    char VerticesProjectedSphere[91]      = "Liste des intersections du polyhèdre projetés sur la sphère" ;
    char EvalStrutelevance[91]            = "Évaluation des poutres pour déterminer leur pertinence" ;
    char HorizontalStruts[91]             = "Poutres Horizontales" ;
    char DiagonalStruts[91]               = "Poutres Diagonales" ;
    char PreOptimizationStruts[91]        = "Groupe maximal de poutres requis à être optimisés pour l'ensemble minimum" ;
    char StrutsAndTheirLengthsAre[91]     = "poutres et leur longeurs sont" ;

#endif /* _cimifrecn_messagestable_fr_h */
//==================================================================================================

从综合主消息文件生成语言特定头文件的脚本:

#!/bin/sh

lang="${1}"

MESSAGE_TABLE="CIMIfrecN_MessagesTable_ALL.h"
MESSAGE_HEADER="CIMIfrecN_MessagesTable_${lang}.h"
Module="_"`echo "${MESSAGE_HEADER}" | tr '[A-Z]' '[a-z]' `
Module=`basename "${Module}" ".h" `"_h"

maxVar=`grep '^V|' "${MESSAGE_TABLE}" | cut -f2- -d\| | 
    while read msg
    do
        echo "${msg}" | wc -c
    done | sort -r | head -1 `

maxStr=`grep '^'${lang}'|' "${MESSAGE_TABLE}" | cut -f2- -d\| | 
    while read msg
    do
        echo "${msg}" | wc -c
    done | sort -r | head -1 `

#echo ${maxStr}

awk -v maxV="${maxVar}" -v maxS="${maxStr}" -v local="${lang}" -v file="${MESSAGE_HEADER}" -v module="${Module}" 'BEGIN{
    var="" ;
    msg=""
    printf("\t local = %s\n", local ) | "cat 1>&2" ; 

    printf("//==================================================================================================\n") ;
    printf("//  FILE:   %s\n", file ) ;
    printf("//  Header initializing context-based messages for the program\n") ;
    printf("//==================================================================================================\n") ;
    printf("\n") ;

    printf("#ifndef %s\n", module ) ;   ### Insert "header guard" to avoid double referencing by compiler
    printf("#define %s\n", module ) ;
    printf("\n") ;

    printf("//#include <stdio.h>\n") ;
    printf("//#include <stdlib.h>\n") ;
    printf("//#include <string.h>\n") ;
    printf("\n") ;
}{
    switch( $0 ){
        case /\|/ :
            #printf("\n %s\n", $1 ) ;
            gsub( "\015", "", $0 );

            split( $0, dat, "|" ) ;

            if( dat[1] == "V" ){
                var=dat[2] ;
                #printf("\n\t %s\n", var ) ;
            }else{
                #printf("\n %s\n", $1 ) ;
                if( dat[1] ~ local ){
                    msg=dat[2] ;
                    #printf("\n\t %s\n", msg ) ;
                } ;
            } ;
        
            if( var != "" && msg != "" ){ 
                #printf("\n\t\t var = %s\n", var ) ;
                #printf("\t\t msg = %s\n", msg ) ;
                offset=maxV-length(var)+3 ;
                printf("\tchar %s\133%d\135%"offset"s= %s ;\n", var, maxS, "", msg ) ;
                var=""
                msg=""
            } ;
            break ;
        default :
            break ;
    } ;
}END{
    printf("\n#endif /* %s */\n", module ) ;
    printf("//==================================================================================================\n") ;
}' "${MESSAGE_TABLE}" > "${MESSAGE_HEADER}"

gvim "${MESSAGE_HEADER}"

echo "\n\t Done.\n"
#//3456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+
mbyulnm0

mbyulnm01#

更新答案…
尝试使用此代码…

#include <langinfo.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

// Define preprocessor macros for each language
#ifdef SPANISH
#define MYLANG "es_MX:es"
#include "CIMIfrecN_MessagesTable_es.h"
#endif

#ifdef FRENCH
#define MYLANG "fr_CA:fr"
#include "CIMIfrecN_MessagesTable_fr.h"
#endif

#ifdef ENGLISH
#define MYLANG "en_CA:en"
#include "CIMIfrecN_MessagesTable_en.h"
#endif

//==================================================================================================
//  START OF MAIN PROGRAM
//==================================================================================================

int main() {
    char yellowON[12] = "\e[93;1m";
    char yellowOFF[12] = "\e[0m";

    char redON[12] = "\e[91;1m";
    char redOFF[12] = "\e[0m";

    char blueON[12] = "\e[94;1m";
    char blueOFF[12] = "\e[0m";

    char ThisLOCALE[30];

    sprintf(ThisLOCALE, "%s", setlocale(LC_ALL, ""));
    printf("\n\t %s\n\n", ThisLOCALE);

    printf("Selected language: %s\n", MYLANG);

    printf("\n  == %s%s%s ==\n", blueON, ScenarioSetUp, blueOFF);

    return 0;
}

现在,您应该能够使用适当的语言预处理器宏来编译程序,以便在编译时选择所需的语言。例如,为西班牙语编译:
爆...

gcc -DSPANISH -o my_program my_program.c

法语:

gcc -DFRENCH -o my_program my_program.c

或英语:

gcc -DENGLISH -o my_program my_program.c

每次编译都将包含相应的语言特定的头文件,并相应地设置MYLANG宏,允许您在编译时在语言之间切换。
我不相信你需要对你的“从综合主消息文件生成语言特定头文件的脚本”进行任何更改。
您的Include文件似乎也很好...请记住,每个特定于语言的消息文件都应该遵循类似的结构,并具有该语言的相同消息的翻译。这样,当您使用预处理器宏基于所选语言包含这些文件时,您的程序将使用相应的语言特定的翻译。
假设您已经对其他每个语言特定的消息文件(例如,CIMIfrecN_MessagesTable_es.h、CIMIfrecN_MessagesTable_en.h)进行了类似的更改,我认为结构应该可以正确工作。

toe95027

toe950272#

C演示程序的最终工作版本,使用我理解的@masonthedev方式概述的方法,如下所示:

/*##################################################################################################
###
### $Id: $
###
### C source code for demonstrating usage of compiler directive for selecting a language specific header file for standardized messages used by a given program.
###
### The program expects the compiler command to include the passing of a language
### identification string, i.e. "Español" for the compiler to make
### the correct selection from an itemized list of scenarios.
###
### It is recommended that the header filenames make use of the
### ISO standardized 2-letter labels for the language identifier.
###
### This demo program also calls the LOCALE identification function directly for a comparison
### of the value identified and reports both that value and the first message variable's value
### defined in the header file for visual comparison
### as a sanity check that all went as expected/desired.
###
####################################################################################################
*/

#include <langinfo.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef Español
#include "CIMIfrecN_MessagesTable_es.h"
//#define MYLANG "es_MX:es"
    char MYLANG[15] = "es" ;
#define LANGSET 1
#endif

#ifdef Français
#include "CIMIfrecN_MessagesTable_fr.h"
//#define MYLANG "fr_CA:fr"
    char MYLANG[15] = "fr" ;
#define LANGSET 1
#endif

#ifdef English
#include "CIMIfrecN_MessagesTable_en.h"
//#define MYLANG "en_CA:en"
    char MYLANG[15] = "en" ;
#define LANGSET 1
#endif

#if LANGSET != 1
// Failsafe if language directive not set or not recognized
#include "CIMIfrecN_MessagesTable_en.h"
//#define MYLANG "en_CA:en"
    char MYLANG[15] = "en" ;
#endif


//==================================================================================================
//  START OF MAIN PROGRAM
//==================================================================================================

//int setProgramLOCALE(){
int main(){

    char yellowON[12]="\e[93;1m" ;
    char yellowOFF[12]="\e[0m" ;

    char redON[12]="\e[91;1m" ;
    char redOFF[12]="\e[0m" ;

    char blueON[12]="\e[94;1m" ;
    char blueOFF[12]="\e[0m" ;

    char ThisLOCALE[30] ;

    sprintf( ThisLOCALE, "%s", setlocale(LC_ALL, "") ) ;
    printf("\n\t %s\n\n", ThisLOCALE ) ;

    printf("\t Selected language: %s\n", MYLANG);

    printf("\n\t == %s%s%s ==\n\n", blueON, ScenarioSetUp, blueOFF ) ;

    return 0;
}

它是用

g++ -DEnglish -Wall -w -o CIMIfrecN_GetMessageArray_LOCALE__TESTOR CIMIfrecN_GetMessageArray_LOCALE__TESTOR.cpp

结果输出如所需:

en_CA.UTF-8

Selected language: en

== Scenario Set-Up ==

使用**-DBOGUS测试#ifndef LANGSET**,确认故障保护选项(* 临时设置为与本地值不同的值 *)实际上被正确触发,从而确认逻辑。
我创建了一个 Package 器脚本来处理预编译设置:

#!/bin/sh

####################################################################################################
###
### $Id: Compile_Manually.sh,v 1.1 2023/10/07 22:55:30 ericthered Exp ericthered $
###
### Script to compile programs using compiler directive for each user's own locale with a view to selecting a language specific header file for standardized messages used by the program.
###
### The script will signal the compiler which of the locale-specific
### message header files will be used during compile time.
###
### This script does not care what the name of the language-specific header files are.
### Those are expected to be defined within the compiler directives of the Program being compiled.
###
### The --debug option allows the user to test the LOCALE functionality by
###     - probing the environment and reporting LOCALE specific information, and
###     - using an EXAMPLE program demonstrating how that is incorporated via compiler directives.
###
####################################################################################################

probe_LOCALE(){
    echo "\t CMD: locale"
    locale
    echo "==============================================\n"

    echo "\t CMD: localectl status"
    localectl status
    echo "==============================================\n"

    echo "\t CMD: locale -k LC_TIME"
    locale -k LC_TIME
    echo "==============================================\n"
} #END probe_LOCALE()

##3456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+

DBG=0
while [ $# -gt 0 ]
do
    case "$1" in
        "--debug" )
            DBG=1
            probe_LOCALE
            ### Program for demonstrating proper handling of LOCALE defined in the environment
            Program="CIMIfrecN_GetMessageArray_LOCALE__TESTOR.cpp"
            OpenGL_Module_API=""
            echo "\n DEBUG MODE:  Using demo program '${Program}' ...\n"
            shift
            break
            ;;
        "--program" )
            Program="$2"
            #Program="CIMIfrecN_GetMessageArray_LOCALE.cpp"
            OpenGL_Module_API="glad.c -ldl -lglfw"
            echo "\n PRODUCTION MODE:  Including 'GLAD' API files for runtime integration of OpenGL  ...\n"
            shift ; shift
            ;;
        * )
            echo "\n\t Invalid parameter used on the command line.\n\n\t Only valid options:  [--debug] [--program {C_source_file} ]\n\n"
            exit 1
            ;;
    esac
done

if [ -z "${Program}" ]
then
    Program="CIMIfrecN_GetMessageArray_LOCALE__TESTOR.cpp"
fi

Execute=`basename "${Program}" ".cpp" `

if [ -n "${LANGUAGE}" ]
then
    myLANG=`echo "${LANGUAGE}" | cut -f1 -d\_ `

    case "${myLANG}" in
        "es" )  myLANG="Español" ;;
        "en" )  myLANG="English" ;;
        "fr" )  myLANG="Français" ;;
#       "de" )  myLANG="Deutsch" ;;
#       "it" )  myLANG="Italiano" ;;
#       "nl" )  myLANG="Nederlandse" ;;
#       "pl" )  myLANG="Polski" ;;
#       "ja" )  myLANG="日本語" ;; # Japanese
#       "in" )  myLANG="Hindi ;;    # Hindi (India)
#       "zh" )  myLANG="简体中文" ;;    # simplified Chinese
#       "pt" )  myLANG="Português" ;;
#       "tr" )  myLANG="Türkçe" ;;
#       "ru" )  myLANG="Русский" ;; # Russian
#       "fa" )  myLANG="ﯽﺳﺭﺎﻓ" ;;   # Persian
#       "ar" )  myLANG="ﺔﻴﺑﺮﻌﻟﺍ" ;; # Arabic
#       "he" )  myLANG="תירִבְעִ" ;;    # Hebrew
        * )
            ### Failsafe default language setting
            myLANG="English" ;;
    esac
else
    ### Failsafe default language setting
    myLANG="English"
fi

#myLANG="BOGUS"

if [ $DBG -eq 1 ]
then
    ### Permanent code for DEBUG mode
    echo \ g++ -D${myLANG} -Wall -w -o "${Execute}" "${Program}" "${OpenGL_Module_API}"
else
    ### Temporary code for PRODUCTION mode
    echo \ g++ -D${myLANG} -Wall -w -o "${Execute}" "${Program}" "${OpenGL_Module_API}"
fi

eval g++ -D${myLANG} -Wall -w -o "${Execute}" "${Program}" "${OpenGL_Module_API}"

if [ $? -eq 0  -a  -s "${Execute}" ]
then
    echo "\n The code has been compiled as '${Execute}'.  You may run that now ...\n"
fi

我现在可以在完整程序的源代码中实现了。
感谢所有对这位学习者/求知者在掌握之路上的进步做出贡献的人。

jexiocij

jexiocij3#

在C语言中,没有一个与sprintf函数直接等价的函数可以在#define指令中使用。C中的#define指令由预处理器处理,预处理器在编译时操作,并且不能访问字符串格式化等运行时操作。
在您的特定情况下,您希望在#define指令中仅获取字符串的前2个字符,您不能直接使用像sprintf这样的函数。
但是,您可以尝试在#define指令中手动指定字符串的前两个字符。

#define MYLANG LANG[0], LANG[1]

这假定LANG是代码中定义的常量或变量,并且在预处理时,MYLANG将替换为LANG的前两个字符。

相关问题