2016-12-16 61 views
2

我做了一個非常簡單的程序調用分叉和調用另一個問題。雖然它做我想做的事情,一個錯誤發生和cout發生雙循環的次數。下面是代碼: 的main.cpp產卵的孩子和執行未定義的行爲

`#include <iostream> 
#include <cstdlib> 

#include <stdio.h> 
#include <string.h> 
#include <time.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/ipc.h> 

using namespace std; 

char *Strduplicate(const char *source) { 
    char *dest = (char *) malloc(strlen(source) + 1); // +1 = '\0' 
    if (dest == NULL) 
     return NULL; 
    strcpy(dest, source); 
    return dest; 
} 

string Get_cwd(string word) { 
    char cwd[256]; 
    getcwd(cwd, sizeof(cwd)); 
    strcat(cwd,"/"); 
    strcat(cwd,word.c_str()); 
    string returnVal(cwd); 
    return returnVal; 
} 

void Call_exec(const char *name,int value) { 
    char *exec_array[3]; 
    exec_array[0] = Strduplicate(name); 
    exec_array[1] = (char *)malloc(2); 
    exec_array[1] = (char *)"-m"; 
    asprintf(&(exec_array[2]), "%d", value); 
    for (int i = 0 ; i < 3; i++) 
     cout << exec_array[i] << " "; 
    cout << endl; 
    execv(exec_array[0],exec_array); 
} 

int main(int argc ,char **argv) { 
    srand(time(NULL)); 
    /* Getting arguments */ 
    //........ 
    /* Spawning children */ 
    for (int i = 0 ; i < 3 ; i++) { 
     int value = rand()%100 + 1; 
     pid_t waiterpid = fork(); 
     if (waiterpid < 0) 
      cout << "ERROR FORK" << endl; 
     else if (!waiterpid) { 
      string program_name = Get_cwd("child"); 
      Call_exec(program_name.c_str(),value); 
     } 
    } 
    return EXIT_SUCCESS; 
} 
` 

和其他進程child.cpp

#include <iostream> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 

using namespace std; 

int main(int argc ,char **argv) { 
    cout << "Child #" << getpid() << " has started" << endl; 
    int value; 
    /* Getting arguments */ 
    if (argc != 3) { 
     cerr << "ERROR : Wrong arguments" << endl; 
     exit(EXIT_FAILURE); 
    } 
    else { 
     if (strncmp(argv[1],"-m",2) == 0) 
      value = atoi(argv[2]); 
    } 
    cout << "Child has " << value << endl; 
    return EXIT_SUCCESS; 
} 

輸出

mypath/child -m 31 
mypath/child -m 23 
mypath/child -m 48 
mypath/child -m 23 
mypath/child -m 48 
[email protected]$ Child #13063 has started 
Child #13062 has started 
Child has 48 
Child has 23 
mypath/child -m 48 
Child #13064 has started 
Child has 48 

所以我誤會嗎?

+0

如果你正在學習C++,那麼這段代碼的一半是UB或者不符合標準的非標準(從頭文件的使用開始..)。如果它的導師要求不使用C++的_features_,考慮考慮替代方案並牢記。 – Swift

+0

例如包括stdlib.h是UB​​,儘管你已經在包含正確的頭文件cstdlib之後做了這個。包括string.h也是錯誤的。 '在_global_作用域中使用namespace std'可能會導致可能的UB,儘管不在這個片段中。再也沒有STL了,STL是一個單獨的庫,可能出於歷史原因,如果你有iostream,你已經在使用C++模板庫(不是STL)。不要在C++代碼中使用malloc \ free \ realloc,使用new和delete(以及新的位置)。 – Swift

回答

1

這裏誤解了編寫現代C++代碼的一般原則。沒有任何理由使用這些可怕的C型動態內存分配。這裏所做的一切都可以做得更乾淨,使用容器,結果代碼至少小三倍。

噢,execv的參數數組必須以NULL指針終止。它不是,所以這會導致未定義的行爲。根據我對手冊頁的細讀,最有可能的是,execv系統調用失敗,因爲這個垃圾參數 - 很可能是EFAULT。因此,execv()實際上在子進程中返回。由於所顯示的代碼未能檢查其返回值:隨機的子進程將在從execv()返回時繼續執行,在子進程中返回main(),並繼續執行其自己的外部旋轉循環for循環,從而導致重複輸出。

+0

STL是不允許的,因爲我想動態執行,所以我不能使用execl,所以這就是爲什麼我最終這樣做。 –