C 我怎样才能减少我的程序大小
C how can I decrease my program size
我正在为 uController 编写一个 c 程序,我设法用代码填充了 32kb。
该程序包含以下 'print' 功能:
void print(char *x)
{
while(*x) {
SerialWrite(*x++);}
}
SerialWrite 看起来像:
void SerialWrite(unsigned char c)
{
while(tx_buffer_size>250);
ES=0;
tx_buffer_size++;
if (tx_buffer_empty == 0){
txBuffer[tx_in++] = c;}
else {
tx_buffer_empty = 0;
SBUF = c;}
ES=1;
}
我用字符串文本作为参数调用打印函数,例如:
print("Hello World");
我只使用了 32kb 外部存储器中的 2.2kb,所以我的结论是 "Hello World" 移动到外部存储器而不是在主程序中硬编码。
不幸的是,我的尝试实际上让事情变得更糟,我做了以下事情:
char xdata *msg1 = "Hello World"; // <-- this made it worse, and the external memory space was not used at all
print(msg1);
比我试过:
char xdata msg1[] = "Hello World";
print(msg1);
这确实将外部存储器大小增加了 12 个,这是正确的,因为字符串包含 11 个字符 + 空值。但是程序内存也增加了3。我尝试了不同的字符串长度,但是程序内存一直增加3字节。
我该如何解决这个问题?
补充:
我正在使用 Keil 的 C 编译器,并且我在编译时会考虑程序大小。
uController 是一个 FPGA 芯片,它有一个仿真的 80C51 芯片。对于这个虚拟 80c51,我正在编写代码。我有 32kb 的主程序内存和 32kb 的变量
编辑:*msg[] 打错了,应该是 *msg
简而言之,将此行放在源文件的开头:
#pragma STRING (XDATA)
这些页面可以帮助您更好地理解:
http://www.keil.com/support/man/docs/c51/c51_le_const.htm
http://www.keil.com/support/man/docs/c51/c51_string.htm
2018/06/25 编辑:
试试这一行:
#pragma O2 STRING (XDATA)
如上文第二个 link 和本页所述,应启用 OMF2 以使用 STRING 指令
http://www.keil.com/support/man/docs/c51/c51_omf2.htm
char xdata *msg1 = "Hello World";
char xdata msg1[] = "Hello World";
我不认为你可以用这种方式缩短你的程序,因为即使消息将被访问来自 xdata,它也会首先被 C 运行时复制到那里,从代码(初始化数据)中获取它。
如果你真的有很多“print()”,那么你可以通过为其参数声明一个正确的指针类型来压缩一些字节。我解释一下:由于 8051 的奇怪架构,“高级”C“通用”指针需要三个字节 - 两个字节作为偏移量,第三个字节指定它是指向 XDATA 还是指向 CODE。那么每次调用print()都要构造这样一个指针。
例如,如果您声明:
void print(char xdata *x)
现在 print() 只接受指向 xdata 的指针,并且只需要两个字节长的指针。每次调用 print() 都会更简单。
看来你的大部分文字都是不变的,所以都是代码;所以你需要的指针类型是 不是 XDATA 而是 CODE (或者其他关键字是正确的).
一旦您像上面那样声明了 print() ,您将无法再打印不在代码段中的数据;也许你需要另一个功能,比如
printx(char* what)
它将接受来自任何段的 char*,就像以前一样,但您将仅在需要时才调用这个昂贵的 printx()。
希望这对您有所帮助; 8051 非常奇特,它的编译器很复杂(但 Keil 非常棒)。我建议查看生成的(低级)代码,也许您可以发现其他一些内存浪费。祝你好运!
附录:______________
有一次我没有足够的空间放文字。我通过应用一些文本压缩很好地解决了问题。鉴于所有文本都是纯 ASCII,我使用超过 127 个字符来指向文本中常见的重复单词。例如,如果字符串“Hello”重复几次,“Hello world”可以替换为 0x80 " world"
。当然,打印例程必须检测那些特殊标记并管理解压缩 - 但这非常容易。
我正在为 uController 编写一个 c 程序,我设法用代码填充了 32kb。
该程序包含以下 'print' 功能:
void print(char *x)
{
while(*x) {
SerialWrite(*x++);}
}
SerialWrite 看起来像:
void SerialWrite(unsigned char c)
{
while(tx_buffer_size>250);
ES=0;
tx_buffer_size++;
if (tx_buffer_empty == 0){
txBuffer[tx_in++] = c;}
else {
tx_buffer_empty = 0;
SBUF = c;}
ES=1;
}
我用字符串文本作为参数调用打印函数,例如:
print("Hello World");
我只使用了 32kb 外部存储器中的 2.2kb,所以我的结论是 "Hello World" 移动到外部存储器而不是在主程序中硬编码。
不幸的是,我的尝试实际上让事情变得更糟,我做了以下事情:
char xdata *msg1 = "Hello World"; // <-- this made it worse, and the external memory space was not used at all
print(msg1);
比我试过:
char xdata msg1[] = "Hello World";
print(msg1);
这确实将外部存储器大小增加了 12 个,这是正确的,因为字符串包含 11 个字符 + 空值。但是程序内存也增加了3。我尝试了不同的字符串长度,但是程序内存一直增加3字节。
我该如何解决这个问题?
补充: 我正在使用 Keil 的 C 编译器,并且我在编译时会考虑程序大小。 uController 是一个 FPGA 芯片,它有一个仿真的 80C51 芯片。对于这个虚拟 80c51,我正在编写代码。我有 32kb 的主程序内存和 32kb 的变量
编辑:*msg[] 打错了,应该是 *msg
简而言之,将此行放在源文件的开头:
#pragma STRING (XDATA)
这些页面可以帮助您更好地理解:
http://www.keil.com/support/man/docs/c51/c51_le_const.htm http://www.keil.com/support/man/docs/c51/c51_string.htm
2018/06/25 编辑: 试试这一行:
#pragma O2 STRING (XDATA)
如上文第二个 link 和本页所述,应启用 OMF2 以使用 STRING 指令 http://www.keil.com/support/man/docs/c51/c51_omf2.htm
char xdata *msg1 = "Hello World";
char xdata msg1[] = "Hello World";
我不认为你可以用这种方式缩短你的程序,因为即使消息将被访问来自 xdata,它也会首先被 C 运行时复制到那里,从代码(初始化数据)中获取它。
如果你真的有很多“print()”,那么你可以通过为其参数声明一个正确的指针类型来压缩一些字节。我解释一下:由于 8051 的奇怪架构,“高级”C“通用”指针需要三个字节 - 两个字节作为偏移量,第三个字节指定它是指向 XDATA 还是指向 CODE。那么每次调用print()都要构造这样一个指针。
例如,如果您声明:
void print(char xdata *x)
现在 print() 只接受指向 xdata 的指针,并且只需要两个字节长的指针。每次调用 print() 都会更简单。
看来你的大部分文字都是不变的,所以都是代码;所以你需要的指针类型是 不是 XDATA 而是 CODE (或者其他关键字是正确的).
一旦您像上面那样声明了 print() ,您将无法再打印不在代码段中的数据;也许你需要另一个功能,比如
printx(char* what)
它将接受来自任何段的 char*,就像以前一样,但您将仅在需要时才调用这个昂贵的 printx()。
希望这对您有所帮助; 8051 非常奇特,它的编译器很复杂(但 Keil 非常棒)。我建议查看生成的(低级)代码,也许您可以发现其他一些内存浪费。祝你好运!
附录:______________
有一次我没有足够的空间放文字。我通过应用一些文本压缩很好地解决了问题。鉴于所有文本都是纯 ASCII,我使用超过 127 个字符来指向文本中常见的重复单词。例如,如果字符串“Hello”重复几次,“Hello world”可以替换为 0x80 " world"
。当然,打印例程必须检测那些特殊标记并管理解压缩 - 但这非常容易。