国际化C程序

时间:2015-06-16 18:30:01

标签: c

目前我用英语为某些嵌入式设备编写了C程序。 所以有代码如:

SomeMethod("Please select menu");
OtherMethod("Choice 1");

现在,说我想支持其他语言。但是因为我不知道我对这个设备有多少内存(可能很少可能更多)我不想在我可能占用更少的空间并使程序崩溃。所以我希望新方法将字符串存储在相同的内存区域并占用相同的空间。所以我想到了这个:

SomeMethod(SELECT_MENU);
OtherMethod(CHOICE_1);

一个单独的头文件:

Engligh.h

#define SELECT_MENU "Please select menu"
#define CHOICE_1 "Choice 1"

对于其他语言:

French.h

#define SELECT_MENU "Text in french"
#define CHOICE_1 "same here"

现在根据我想要的语言,我只会包含该头文件。

这是否满足要求如果我选择英文版我的国际化程序' strings存储在同一个内存区域上并占用与前一个相同的内存? (我知道法语可能需要更多 - 但这是与法语字母占用更多字节相关的其他问题)。

我想,因为我将使用defines字符串将被放置在它们之前的内存中的相同位置。

5 个答案:

答案 0 :(得分:6)

至少在Linux和许多其他POSIX系统上,你应该对gettext(3)感兴趣(以及printf(3)中的定位参数,例如%3$d而不是%d控制格式字符串)。

然后你会编码

 printf(gettext("here x is %d and y is %d"), x, y);

这很常见,有习惯

#define _(X) gettext(X)

以及稍后的代码

printf(_("here x is %d and y is %d"), x, y);

您还希望使用msgfmt(1)

处理邮件目录

您可以找到有关国际化( i18n )和本地化的多个文档,例如: Debian Introduction to i18n。另请阅读locale(7)。你今天可能应该总是使用UTF-8

此类消息目录的优势(默认情况下,这一切在Linux系统上已经可用!)是国际化在运行时发生。没有理由限制它在编译时发生。消息目录可以(通常是)由开发人员的其他人翻译。您将在文件系统中有目录(例如在一些廉价的闪存中,如某些SD芯片),包含这些目录。

请注意国际化&本地化是一个困难的主题(阅读更多文档,了解它有多难,一旦你想要处理非欧洲语言),Linux基础设施设计得相当好(可能比你建议的更好,更有效率)用你的宏)。 Qt和Gtk也广泛支持国际化(基于gettext等......)。

答案 1 :(得分:2)

让我直截了当地说:你想知道如果预编译器定义的变量(在你的情况下,与i18n相关)在编译之前被换掉,那么他们会(a)占用相同的内存量(宏观和非宏版本之间)和(b)存储在同一程序段

简短回答是(a)和(b)是 - 是

对于第一部分,这很容易。预处理器定义的常量在传递到编译器之前由预处理器替换为它们的#define'd值。所以,对编译器来说,

#define SELECT_MENU "Please select menu"
// ...
SomeMethod(SELECT_MENU);

读入
SomeMethod("Please select menu");

因此除了对程序员的看法外,所有意图和目的都是相同的。

对于第二部分,这有点复杂。如果在C程序中有常量字符串文字,它们将被分配到程序的data segment或(如果被声明为自分配char数组的初始内容)在程序的{{ {3}}并存储在堆栈或堆上,如果我没有记错的话(如code segment的答案中所讨论的那样)。这取决于程序中如何使用预处理程序定义的常量

考虑到我在第一部分中所说的,如果你有char buffer[] = MY_CONSTANT;,它很可能被存储为堆空间分配器和初始化器,它在程序中使用它,并将增加代码细分(可能还有 BSS )。如果您有someFunction(MY_CONSTANT);char* c_str = MY_CONSTANT;,那么它可能会存储在数据段中,您将在运行时收到指向该区域的指针。这可能会在您的实际计划中体现出很多种方式;变量#define'd 不能可靠地确定它们将如何存储在已编译的程序中尽管如果它们仅以某种方式使用,那么您可以合理地确定它将被存储在哪里

编辑由于@ esm的评论,修改了上半部分的答案以准确地解决所提出的问题。

答案 2 :(得分:1)

要回答问题,这会占用相同的内存量,并且在使用英语非非宏版本的程序的相同部分中将字符串放在英语宏版本答案是肯定的。

C预处理器(CPP)将使用给定语言的正确语言字符串替换宏的所有实例,并且在CPP运行之后,它将仿佛宏从未存在。字符串仍将放在read only data section of the binary, assuming that is supported中,就像您没有使用宏一样。

所以用宏来总结英文版本,没有宏的英文版本就考虑到C编译器是一样的,see link

答案 3 :(得分:1)

您这样做的方式,如果您将程序编译为英语,那么法语单词将不会存储在程序的英文版本中。

编译器甚至不会看到法语单词。法语单词不会出现在最终的可执行文件中。

在某些情况下,编译器可能会看到一些数据,但如果数据未在程序中使用,它会选择忽略该数据。

例如,考虑这个功能:

void foo() {
    cout << "qwerty\n";
}

如果你定义了这个函数,但是你没有在程序中使用它,那么函数foo和字符串&#34; qwerty&#34;在最终的可执行文件中找不到自己的方式。

使用宏并没有任何区别。例如,foo1foo2是相同的。

#define SOME_TEXT "qwerty\n"
void foo2() {
    cout << SOME_TEXT;
}

数据存储在堆中,堆限制通常非常大。除非SOME_TEXT大于堆栈限制(通常大约100 kb)并且此数据正在堆栈中复制,否则不会出现内存不足。

所以除了程序的最终大小之外,你基本上没有什么可担心的。

答案 4 :(得分:1)

这里的预处理器使用是简单的替换:

之间的可执行代码没有区别
SomeMethod("Please select menu");

#define SELECT_MENU "Please select menu"
...
SomeMethod(SELECT_MENU);

但是每种语言的内存使用量不太可能完全相同。

在实践中,消息通常比简单翻译更复杂。例如,在消息中

Input #4 is dangerous

你有吗

#define DANGER "Input #%d is dangerous"
...
printf(DANGER, inpnum); 

或者你会做什么

#define DANGER "Dangerous input #"
...
printf(DANGER); 
printf("%d", inpnum); 

我使用这些示例来表明您必须从一开始就考虑语言版本,而不是简单的后期修复。

因为你提到&#34;一个设备&#34;并且关注内存使用情况,我想你正在使用嵌入式。我自己喜欢的方法是提供包含单词或短语数组的语言模块,#define引用数组元素以用于拼凑消息。这也可以使用enum完成。

例如(实际上会单独包含英文源文件

#include <stdio.h>

char *message[] = { "Input", 
                    "is dangerous" };

#define M_INPUT     0
#define M_DANGER    1

int main()
{
    int input = 4;
    printf ("%s #%d %s\n", message[M_INPUT], input, message[M_DANGER]);
    return 0;
}

节目输出:

Input #4 is dangerous