C++ Arduino,在带有 char 指针参数的方法中使用 sprintf,中断程序
C++ Arduino, use of sprintf inside a method with a char pointer parameter, breaks program
我一天的大部分时间都在处理这个问题,并将其缩小到以下简单程序来复制它:
Test.ino
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
}
// the loop function runs over and over again until power down or reset
void loop() {
char _message[16] = { '[=10=]' };
char *message = _message;
int pins[1] = { 1 };
//testOne(pins, 35, 5); // WORKS!!
testTwo(pins, 35, 5, message); // Desn't Work...
}
void testOne(int sensorPins[], int userDefault, int offset) {
char _int_char[2];
sprintf(_int_char, "%d", 36);
Serial.println(_int_char);
}
void testTwo(int sensorPins[], int userDefault, int offset, char *message) {
char _int_char[2];
sprintf(_int_char, "%d", 37);
Serial.println(_int_char);
}
以上代码所做的就是调用 testOne 和 testTwo 函数。
testOne 函数为循环的每次迭代给出了将值 36 写入序列 window 的预期结果。
testTwo 函数将以下内容写入串行 window:
"VMDPV_1|1_VMVMDPV_1|1_VM".......
只有当我将 char *message 参数添加到函数时才会发生这种情况。
显然,这是一个非常简化的演示,具有硬编码值等......在我的实际代码中,我使用了参数并且还有很多事情要做......
实际上是对 sprintf 的调用导致了问题。在我的实际代码中,我将其用作构建消息的一部分。当我在我的实际代码中注释掉 sprintf 行时,它起作用了。但是我当然需要那一行来将其中一个参数的值获取到消息中。
谁能告诉我为什么 sprintf 在具有 char *message 参数的函数中不起作用?
我正在使用 Arduino UNO,并使用 Visual Micro 1511.23.1 在 Visual Studio 中编写了代码,它是基于已安装的 arduino IDE 设置 1.6.5 构建的。
我也已经能够在 arduino IDE 中复制它,除了我得到的字符与 "VMDPV_1..." 不同......我得到了一个,3 一个带倒置逗号的字母 O在上面和一个正方形。
我正在 Win 10 64 位 PC 上开发所有这些。
感谢您的宝贵时间,
斯科特
在 C 中,字符串以 0 结尾,这意味着在调用 sprintf 之后,_int_char 包含 { '3', '6', '\0' }。这是一个 3 个字符的数组,您只为 2
保留内存
char _int_char[2];
sprintf(_int_char, "%d", 36);
由于缓冲区溢出,您的程序产生了未定义的行为。
char _int_char[2];
sprintf(_int_char, "%d", 37); // <-- buffer overrun
由于生成的字符串可能会占用 2 个以上的字符,多余的字符会溢出 _int_char
数组并覆盖内存。损坏前覆盖内存中的内容可能与参数message
有关。
不是创建 2 个字符的数组,而是声明该数组足够大,不会产生缓冲区溢出。
char _int_char[20];
sprintf(_int_char, "%d", some_integer);
除非您有超过 19 位的整数,否则现在应该不会溢出缓冲区。
一个万无一失的解决方案,因为您使用的是 C++,所以使用 C++ 流,即 std::ostringstream。那么无论要输出的数据长度如何,都不必担心缓冲区溢出:
#include <sstream>
#include <string>
//...
std::string _int_char;
std::ostringstream strm;
strm << some_integer;
_int_char << strm.str();
我一天的大部分时间都在处理这个问题,并将其缩小到以下简单程序来复制它: Test.ino
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
}
// the loop function runs over and over again until power down or reset
void loop() {
char _message[16] = { '[=10=]' };
char *message = _message;
int pins[1] = { 1 };
//testOne(pins, 35, 5); // WORKS!!
testTwo(pins, 35, 5, message); // Desn't Work...
}
void testOne(int sensorPins[], int userDefault, int offset) {
char _int_char[2];
sprintf(_int_char, "%d", 36);
Serial.println(_int_char);
}
void testTwo(int sensorPins[], int userDefault, int offset, char *message) {
char _int_char[2];
sprintf(_int_char, "%d", 37);
Serial.println(_int_char);
}
以上代码所做的就是调用 testOne 和 testTwo 函数。
testOne 函数为循环的每次迭代给出了将值 36 写入序列 window 的预期结果。
testTwo 函数将以下内容写入串行 window: "VMDPV_1|1_VMVMDPV_1|1_VM".......
只有当我将 char *message 参数添加到函数时才会发生这种情况。 显然,这是一个非常简化的演示,具有硬编码值等......在我的实际代码中,我使用了参数并且还有很多事情要做......
实际上是对 sprintf 的调用导致了问题。在我的实际代码中,我将其用作构建消息的一部分。当我在我的实际代码中注释掉 sprintf 行时,它起作用了。但是我当然需要那一行来将其中一个参数的值获取到消息中。
谁能告诉我为什么 sprintf 在具有 char *message 参数的函数中不起作用?
我正在使用 Arduino UNO,并使用 Visual Micro 1511.23.1 在 Visual Studio 中编写了代码,它是基于已安装的 arduino IDE 设置 1.6.5 构建的。
我也已经能够在 arduino IDE 中复制它,除了我得到的字符与 "VMDPV_1..." 不同......我得到了一个,3 一个带倒置逗号的字母 O在上面和一个正方形。
我正在 Win 10 64 位 PC 上开发所有这些。
感谢您的宝贵时间,
斯科特
在 C 中,字符串以 0 结尾,这意味着在调用 sprintf 之后,_int_char 包含 { '3', '6', '\0' }。这是一个 3 个字符的数组,您只为 2
保留内存char _int_char[2];
sprintf(_int_char, "%d", 36);
由于缓冲区溢出,您的程序产生了未定义的行为。
char _int_char[2];
sprintf(_int_char, "%d", 37); // <-- buffer overrun
由于生成的字符串可能会占用 2 个以上的字符,多余的字符会溢出 _int_char
数组并覆盖内存。损坏前覆盖内存中的内容可能与参数message
有关。
不是创建 2 个字符的数组,而是声明该数组足够大,不会产生缓冲区溢出。
char _int_char[20];
sprintf(_int_char, "%d", some_integer);
除非您有超过 19 位的整数,否则现在应该不会溢出缓冲区。
一个万无一失的解决方案,因为您使用的是 C++,所以使用 C++ 流,即 std::ostringstream。那么无论要输出的数据长度如何,都不必担心缓冲区溢出:
#include <sstream>
#include <string>
//...
std::string _int_char;
std::ostringstream strm;
strm << some_integer;
_int_char << strm.str();