C : printf 以混合顺序打印变量
C : printf printing variables in the mixed order
这是我的代码,
#include <time.h>
#include <pthread.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
unsigned sleep(unsigned sec) ;
void get_time(char *buf) {
time_t t = time(NULL) ;
struct tm tm = *localtime(&t) ;
sprintf(buf,"%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec) ;
}
void *calculateSize(uint64_t size, char *buf) {
if (size < 1024ULL){
sprintf(buf, "%.1f %s", (float) size, "B") ;
return NULL ;
}
else if (size < (1024 * 1024)) {
sprintf(buf, "%.1f %s", (float) size/1024ULL, "KiB") ;
return NULL ;
}
else if (size > (1024 * 1024)) {
sprintf(buf, "%.1f %s", (float) size/(1024ULL * 1024ULL), "MiB") ;
return NULL ;
}
strcpy(buf, "0") ;
return NULL ;
}
void * run(char *interface, char * download_buf, char * upload_buf) {
unsigned long rdiff,tdiff ;
unsigned long rx_old,rx_new ;
unsigned long tx_old,tx_new ;
char buf[10] ;
char rx_file[512] ;
char tx_file[512] ;
sprintf(rx_file, "/sys/class/net/%s/statistics/rx_bytes", interface) ;
sprintf(tx_file, "/sys/class/net/%s/statistics/tx_bytes", interface) ;
FILE *rf = fopen(rx_file,"r") ;
FILE *tf = fopen(tx_file,"r") ;
if (rf != NULL && tf != NULL) {
fscanf(rf,"%lu", &rx_old) ;
fscanf(tf,"%lu", &tx_old) ;
fclose(rf) ;
fclose(tf) ;
}
else {
return NULL ;
}
sleep(1) ;
rf = fopen(rx_file,"r") ;
tf = fopen(tx_file,"r") ;
if (rf != NULL && tf != NULL) {
fscanf(rf,"%lu", &rx_new) ;
fscanf(tf,"%lu", &tx_new) ;
rdiff = rx_new - rx_old ;
tdiff = tx_new - tx_old ;
fclose(rf) ;
fclose(tf) ;
}
else {
return NULL ;
}
calculateSize(rdiff,buf) ;
strcpy(download_buf,buf) ;
calculateSize(tdiff,buf) ;
strcpy(upload_buf,buf) ;
return NULL ;
}
void *net_speed(void *thread_speed_args ) {
char* iface = *(char **)thread_speed_args ;
char carrier_file[512] ;
sprintf(carrier_file,"/sys/class/net/%s/carrier", iface) ;
printf("Reading from %s\n", carrier_file) ;
while(1) {
if( access( carrier_file, F_OK ) == 0 ) {
run(iface, ((char **)thread_speed_args)[1], ((char **)thread_speed_args)[2]) ;
}
else {
sprintf(((char **)thread_speed_args)[1],"000 B") ;
sprintf(((char **)thread_speed_args)[2],"000 B") ;
sleep(1) ;
}
}
return NULL ;
}
int main(int argc, char *argv[]) {
char time_buf[10] ; //hh:mm:ss : 8 char + 1 null terminator char
char download_buf[8],upload_buf[8] ;
char* thread_speed_args[3] = { argv[1], download_buf, upload_buf } ;
pthread_t thread_speed ;
pthread_create(&thread_speed, NULL, net_speed, thread_speed_args) ;
pthread_detach(thread_speed) ;
while(1){
get_time(time_buf) ;
printf("Down:%s Up:%s %s\n", thread_speed_args[1], thread_speed_args[2], time_buf) ;
fflush(stdout) ;
sleep(1) ;
}
}
我正在使用一个线程在一个接口上持续监控我的无线数据传输速率,我也在打印时间和传输速率。我只是在尝试线程,如果我的编程逻辑不好,请原谅我。
我注意到当我进行速度测试时,输出或打印变得一团糟,如下所示
Down:0.0 B Up:0.0 B 23:49:03
Down:0.0 B Up:0.0 B 23:49:04
Down:0.0 B Up:0.0 B 23:49:05
Down:17.0 KiB9.2 KiB Up:9.2 KiB 23:49:06
Down:5.3 KiB Up:6.5 KiB 23:49:07
Down:3.4 KiB Up:4.1 KiB 23:49:08
Down:400.6 Ki20.3 KiB23:49:09 Up:20.3 KiB23:49:09 23:49:09
Down:918.6 Ki49.6 KiB23:49:10 Up:49.6 KiB23:49:10 23:49:10
Down:912.8 Ki53.5 KiB23:49:11 Up:53.5 KiB23:49:11 23:49:11
Down:959.2 Ki32.2 KiB23:49:12 Up:32.2 KiB23:49:12 23:49:12
Down:711.5 Ki33.8 KiB23:49:13 Up:33.8 KiB23:49:13 23:49:13
看到最后几行了吗?
谁能告诉我这里发生了什么?我该如何更正它?
发生这种情况是因为您同时访问多个线程中的公共资源 - 在本例中为 STDOUT 句柄。在将信息输出到控制台时,您需要同步您的线程——最简单的方法是使用互斥锁。您可以阅读更多 here.
虽然您的线程缺乏任何类型的同步(在极少数情况下会随机混淆您的输出),但这甚至不是您的问题。
这是您的问题:
char download_buf[8],upload_buf[8] ;
char buf[10] ;
strcpy(download_buf,buf) ;
strcpy(upload_buf,buf) ;
您正在将一个最多 9 个字符的字符串复制到一个 7 个字符的字符串中,从而导致缓冲区溢出。由于缓冲区恰好在堆栈上彼此相邻,因此第二个 strcpy 将覆盖第一个字符串的 0 终止符。与 time_buf 覆盖第二个字符串的 0 终止符相同。
由于缓冲区溢出,总体上有很多未定义的行为。
这是我的代码,
#include <time.h>
#include <pthread.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
unsigned sleep(unsigned sec) ;
void get_time(char *buf) {
time_t t = time(NULL) ;
struct tm tm = *localtime(&t) ;
sprintf(buf,"%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec) ;
}
void *calculateSize(uint64_t size, char *buf) {
if (size < 1024ULL){
sprintf(buf, "%.1f %s", (float) size, "B") ;
return NULL ;
}
else if (size < (1024 * 1024)) {
sprintf(buf, "%.1f %s", (float) size/1024ULL, "KiB") ;
return NULL ;
}
else if (size > (1024 * 1024)) {
sprintf(buf, "%.1f %s", (float) size/(1024ULL * 1024ULL), "MiB") ;
return NULL ;
}
strcpy(buf, "0") ;
return NULL ;
}
void * run(char *interface, char * download_buf, char * upload_buf) {
unsigned long rdiff,tdiff ;
unsigned long rx_old,rx_new ;
unsigned long tx_old,tx_new ;
char buf[10] ;
char rx_file[512] ;
char tx_file[512] ;
sprintf(rx_file, "/sys/class/net/%s/statistics/rx_bytes", interface) ;
sprintf(tx_file, "/sys/class/net/%s/statistics/tx_bytes", interface) ;
FILE *rf = fopen(rx_file,"r") ;
FILE *tf = fopen(tx_file,"r") ;
if (rf != NULL && tf != NULL) {
fscanf(rf,"%lu", &rx_old) ;
fscanf(tf,"%lu", &tx_old) ;
fclose(rf) ;
fclose(tf) ;
}
else {
return NULL ;
}
sleep(1) ;
rf = fopen(rx_file,"r") ;
tf = fopen(tx_file,"r") ;
if (rf != NULL && tf != NULL) {
fscanf(rf,"%lu", &rx_new) ;
fscanf(tf,"%lu", &tx_new) ;
rdiff = rx_new - rx_old ;
tdiff = tx_new - tx_old ;
fclose(rf) ;
fclose(tf) ;
}
else {
return NULL ;
}
calculateSize(rdiff,buf) ;
strcpy(download_buf,buf) ;
calculateSize(tdiff,buf) ;
strcpy(upload_buf,buf) ;
return NULL ;
}
void *net_speed(void *thread_speed_args ) {
char* iface = *(char **)thread_speed_args ;
char carrier_file[512] ;
sprintf(carrier_file,"/sys/class/net/%s/carrier", iface) ;
printf("Reading from %s\n", carrier_file) ;
while(1) {
if( access( carrier_file, F_OK ) == 0 ) {
run(iface, ((char **)thread_speed_args)[1], ((char **)thread_speed_args)[2]) ;
}
else {
sprintf(((char **)thread_speed_args)[1],"000 B") ;
sprintf(((char **)thread_speed_args)[2],"000 B") ;
sleep(1) ;
}
}
return NULL ;
}
int main(int argc, char *argv[]) {
char time_buf[10] ; //hh:mm:ss : 8 char + 1 null terminator char
char download_buf[8],upload_buf[8] ;
char* thread_speed_args[3] = { argv[1], download_buf, upload_buf } ;
pthread_t thread_speed ;
pthread_create(&thread_speed, NULL, net_speed, thread_speed_args) ;
pthread_detach(thread_speed) ;
while(1){
get_time(time_buf) ;
printf("Down:%s Up:%s %s\n", thread_speed_args[1], thread_speed_args[2], time_buf) ;
fflush(stdout) ;
sleep(1) ;
}
}
我正在使用一个线程在一个接口上持续监控我的无线数据传输速率,我也在打印时间和传输速率。我只是在尝试线程,如果我的编程逻辑不好,请原谅我。
我注意到当我进行速度测试时,输出或打印变得一团糟,如下所示
Down:0.0 B Up:0.0 B 23:49:03
Down:0.0 B Up:0.0 B 23:49:04
Down:0.0 B Up:0.0 B 23:49:05
Down:17.0 KiB9.2 KiB Up:9.2 KiB 23:49:06
Down:5.3 KiB Up:6.5 KiB 23:49:07
Down:3.4 KiB Up:4.1 KiB 23:49:08
Down:400.6 Ki20.3 KiB23:49:09 Up:20.3 KiB23:49:09 23:49:09
Down:918.6 Ki49.6 KiB23:49:10 Up:49.6 KiB23:49:10 23:49:10
Down:912.8 Ki53.5 KiB23:49:11 Up:53.5 KiB23:49:11 23:49:11
Down:959.2 Ki32.2 KiB23:49:12 Up:32.2 KiB23:49:12 23:49:12
Down:711.5 Ki33.8 KiB23:49:13 Up:33.8 KiB23:49:13 23:49:13
看到最后几行了吗?
谁能告诉我这里发生了什么?我该如何更正它?
发生这种情况是因为您同时访问多个线程中的公共资源 - 在本例中为 STDOUT 句柄。在将信息输出到控制台时,您需要同步您的线程——最简单的方法是使用互斥锁。您可以阅读更多 here.
虽然您的线程缺乏任何类型的同步(在极少数情况下会随机混淆您的输出),但这甚至不是您的问题。
这是您的问题:
char download_buf[8],upload_buf[8] ;
char buf[10] ;
strcpy(download_buf,buf) ;
strcpy(upload_buf,buf) ;
您正在将一个最多 9 个字符的字符串复制到一个 7 个字符的字符串中,从而导致缓冲区溢出。由于缓冲区恰好在堆栈上彼此相邻,因此第二个 strcpy 将覆盖第一个字符串的 0 终止符。与 time_buf 覆盖第二个字符串的 0 终止符相同。
由于缓冲区溢出,总体上有很多未定义的行为。