提问人:Eric Marceau 提问时间:10/6/2023 最后编辑:Eric Marceau 更新时间:10/8/2023 访问量:165
是否有等效于 awk sprintf 用于 C 编译器 #define 指令
Is there an equivalent to awk sprintf for use in C compiler #define directives
问:
对于上下文,我正在尝试做一些简单的本地化,作为进入“海洋”的第一步,语言选项有限。我想更加“包容”,而不仅仅是局限于逐项列出该类型的所有实例(bash 环境变量 LANGUAGE 值的 3 个选项 )
#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 的单位置引用的拟议方法不起作用。:-(
<附录1>
因此,我尝试了该脚本的修订版本,其中我确实与 LANGUAGE 变量的完整值进行了比较,认为它表明它在预处理期间是可访问的。不幸的是,我没有意识到我将英语作为默认的后备情况,所以我的结论是不正确的。我收到了误报。:-(
...(deleted)...
<附录2>
我再次修改了我的程序,为特定值匹配设置了英语,并添加了特定的字符串来识别遇到哪些无效条件:
#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+
答:
在 C 中,没有直接等效于 sprintf 函数的函数,可以在 #define 指令中使用。C 语言中的 #define 指令由预处理器处理,预处理器在编译时运行,并且无权访问字符串格式等运行时操作。
在特定情况下,如果只想获取 #define 指令中字符串的前 2 个字符,则不能直接使用 sprintf 等函数。
但是,您可以尝试在 #define 指令中手动指定字符串的前两个字符...
#define MYLANG LANG[0], LANG[1]
这假定 LANG 是代码中定义的常量或变量,并且在预处理时,MYLANG 将替换为 LANG 的前两个字符。
评论
更新的答案...
尝试使用此代码...
#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)进行了类似的更改,我认为该结构应该可以正常工作。
评论
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 确认故障安全选项(临时设置为与本地值不同的值)实际上已正确触发,从而确认了逻辑。
我创建了一个包装脚本来处理该预编译设置:
#!/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
我现在可以查看在完整程序的源代码中实现。
感谢所有为这个学习者/寻求者在掌握道路上的进步做出贡献的人。
评论
awk
"es_MX:es"
'es_MX:es'
sprintf("%2s",LANG)
sprintf(buf,"%2s",LANG)
"%.2s"
substr(LANG,1,2)
SPANISH
FRENCH
char MYLANG[2] = {LANG[0], LANG[1]};
that I can use for that?
LC_LANG
LANGAUGE