2017-11-30 32 views
0

Arduino 스케치에서 메모리 사용량을 최소화하기 위해 C++ String 개체 대신 C 문자열을 사용해야합니다. 이것은 내가 고전 C에 익숙하지 않아서 그 자체로 도전이되어왔다.sprintf() 함수를 사용한 후 C 문자열을 읽을 수 없습니다.

그러나 어떻게 든 나는 그것을 (다소간) 작동하게 만들었지 만, 나는 문제를 겪고있다.

#define APIKEY "TWITTER_KEY" // api key ThingSpeak 
#define TARGET_IP "184.106.153.149"///   //local direccion IP o Hosting ThingSpeak 
#define TARGET_PORT "80"   /// puerto 80 
#define ID "WiFi_ID" //name of wireless access point to connect to - Red de inhalambrica wifi 
#define PASS "WiFI_Password" //wifi password       - Contraseña de Wifi 



#define TWEET "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 


char foo[400]; //contains the tweet request 
char bar[20]; //auxiliary 
char numberString[3]; //contains numbers 


void setup() { 

    Serial.begin(9600); 

    testMethod(); 

} 


void testMethod(){ 

    Serial.println(" "); 
    Serial.println("testMethod"); 
    Serial.println(" "); 



    strcpy(foo, "api_key="); 
    strcat(foo, APIKEY); 
    strcat(foo, "&status="); 
    strcat(foo, TWEET); 

    Serial.println(foo); 


    //sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char 


    Serial.println(numberString); 


    // Create HTTP POST Data 


    strcpy(foo, "POST /apps/thingtweet/1/statuses/update HTTP/1.1\n"); 
    strcat(foo, "Host: api.thingspeak.com\n"); 
    strcat(foo, "Connection: close\n"); 
    strcat(foo, "Content-Type: application/x-www-form-urlencoded\n"); 
    strcat(foo, "Content-Length: "); 
    strcat(foo, numberString); 
    strcat(foo, "\n\n"); 
    strcat(foo, "api_key="); 
    strcat(foo, APIKEY); 
    strcat(foo, "&status="); 
    strcat(foo, TWEET); 


    Serial.println(foo); 


    } 




void loop() { 


} 

을 내가

//sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char 

이 나는 ​​시리얼 모니터에 foo을 인쇄 할 수 없습니다 나는 줄을 주석을 오전이나 나는를 인쇄 할 수 있어요 경우 다음 테스트 스케치를 설명하는 것입니다 새 foo가 나중에 생성되었습니다. strlen() 함수 대신 정수를 하드 코딩하면 마찬가지입니다.

나는 이것을 기괴한 행동으로 묘사 할 것이지만, 아마도 내 부분에서 평범한 무지 일 것이다. sprintf() 메서드에 대한 설명서를 읽었지만이 문제와 관련하여 아무 것도 보지 못했습니다.

도움이 될 것입니다. 미리 감사드립니다.

답변

3

strlen(foo)은 3 자리 숫자이므로 numberString에 4 바이트를 할당해야 해당 3 자리수와 NUL 종결자가됩니다.

3

글쎄, 길이가 foo (좋은 변수 이름, btw) 이상인 99 개가 될 수 있으므로 두 자리 이상이 필요합니다. C 문자열은 0으로 끝나는 것입니다. 문자열 "123"의 메모리 표현은 다음과 같습니다

+-+-+-+--+ 
|1|2|3|\0| 
+-+-+-+--+ 

\0 그래서 하나 개 추가 위치가 항상을 유지하는 데 필요한 값 0과 char입니다. 배열을 더 크게 만들어야합니다 :

char numberString[8]; 

안전 측면에 있어야합니다. (%dint입니다 만, strlen() 반환 size_t)

snprintf(numberString, sizeof numberString, "%zu", strlen(foo)); 

은 technially 이후도 유형의 잘못된 경기에서 정의되지 않은 동작을 얻고 : 또한 사용 snprintf() 여기 도왔다.

+0

나는 그렇습니다. 나는 단지 그것을 잊었다. 내가 말했듯이, 무지. 고마워. 첫 번째 정답을 올바른 것으로 표시했습니다. 나는 당신이 이해하기를 바랍니다. – Marcal

1

numberString에 3자를 예약했습니다. 여기에는 종료 영숫자가 포함됩니다. strlen (foo)가 99보다 큰 정수를 반환하면 numberString 버퍼가 오버플로됩니다. 버퍼 오버 플로우 후에 재미있는 일이 발생할 수 있습니다.

+1

Funny 실제로. 고마워. – Marcal

1

NULL 종료 바이트 길이를 제공하지 않는 strlen()에 문제가 있습니다.

char foo[400] = "hello world"; 
// here you allocated the less width, in C strings are the sequence of character bytes terminated with NULL in the end. 
    char number[4]; 

    sprintf(number, "value: %zu\n", strlen(foo));