2013-10-10 9 views
3

Я пытаюсь получить a simple OpenCV sample, работающий на C++ в Windows, и мой C++ более чем ржавый.Преобразование _TCHAR * в char *

The sample довольно прост:

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <iostream> 

using namespace cv; 
using namespace std; 

int main(int argc, char** argv) 
{ 
    if(argc != 2) 
    { 
     cout <<" Usage: display_image ImageToLoadAndDisplay" << endl; 
     return -1; 
    } 
    Mat image; 
    image = imread(argv[1], IMREAD_COLOR); // Read the file 
    if(! image.data)      // Check for invalid input 
    { 
     cout << "Could not open or find the image" << std::endl ; 
     return -1; 
    } 
    namedWindow("Display window", WINDOW_AUTOSIZE); // Create a window for display. 
    imshow("Display window", image);    // Show our image inside it. 
    waitKey(0); // Wait for a keystroke in the window 
    return 0; 
} 

Когда я делаю новый простой C++ консольное приложение (с ATL) в Visual Studio 2012 Я получаю другой шаблон для main:

int _tmain(int argc, _TCHAR* argv[]) 

Так что перед Я отправляю имя файла в функцию imread OpenCV. Мне нужно преобразовать _TCHAR*arg[1] в char*. С помощью простого файла, «OpenCV-logo.jpg», из памяти в окне памяти, я могу видеть, что _TCHAR принимают два байта каждого

o.p.e.n.c.v.-.l.o.g.o...j.p.g... 
6f 00 70 00 65 00 6e 00 63 00 76 00 2d 00 6c 00 6f 00 67 00 6f 00 2e 00 6a 00 70 00 67 00 00 00 

В соответствии с рекомендацией преобразования в another answer Я пытаюсь использовать ATL 7.0 String Conversion Classes and Macros вставив следующий код:

char* filename = CT2A(argv[1]); 

Но в результате память беспорядок, конечно, не 'OpenCV-logo.jpg' как строка ASCII:

fe fe fe fe fe fe fe fe fe fe ... 
þþþþþþþþþþ ... 

Какой метод преобразования, функция или макрос я должен использовать?

(нотабене This может быть связан вопрос, но я не могу видеть, как применять the answer здесь.)

+0

Ваш шаблон проекта пытается создать проект на C++ для поддержки юникода. Я не помню конкретные параметры проекта/компилятора, но должно быть что-то, чтобы указать, использует ли Unicode или нет. – OldProgrammer

+0

Он находится на странице [общая страница свойств проекта] (http://msdn.microsoft.com/en-us/library/vstudio/8x480de8.aspx) – user786653

+0

Вам нужна USES_CONVERSION; в верхней части каждой функции, которая использует макросы преобразования? –

ответ

16

Самое быстрое решение - просто изменить подпись на стандартную.Заменить:

int _tmain(int argc, _TCHAR* argv[]) 

С

int main(int argc, char *argv[]) 

Это означает, на Windows, что аргументы командной строки преобразуются в локали кодирования системы, а с Windows, не поддерживает UTF-8 здесь не все преобразует правильно. Однако, если вам действительно не нужна интернационализация, тогда вам, возможно, не стоит делать больше.

+0

Я пробовал это - я отредактирую вопрос, чтобы объяснить, что (я думаю) пошло не так. – dumbledad

+0

@ dumbledad Хорошо. Комментируйте здесь, когда вы редактируете свой вопрос, чтобы получить уведомление. – bames53

+2

@bames Это работает. В прошлый раз я использовал подпись 'int _tmain (int argc, char ** argv)', а 'char *' в итоге получился как «6f 00 70 00 65 00 6e 00 63 00 76 00 2d 00 6c 00 6f 00 67 00 6f 00 2e 00 6a 00 70 00 67 00 00 00', который является символом 'c', за которым следует' \ 0' плюс больше байтов, то есть строка «c»! Переключение '_tmain' на' main' делает всю разницу, спасибо. – dumbledad

7

_TCHAR, т.е. TCHAR является тип, который зависит от настроек вашего проекта. Это может быть либо wchar_t (когда вы используете Unicode), либо char (при использовании многобайтового). Вы найдете это в Свойства проекта - Общие, есть установка Набор символов.

Вероятно, самое простое, что вы можете сделать, это просто использовать опцию многобайтную и лечения _TCHAR* типа как простой char* и использовать его, чтобы построить std::string объект ASAP:

std::string filename(argv[1]); 

Но в случае вы будете работать со специальными символами A LOT, тогда я считаю более разумным использовать Unicode и удерживать строки в виде объектов std::wstring, где это возможно. Если это так, то просто использовать конструктор std::wstring «s вместо:

std::wstring filename(argv[1]); 

И в случае, если вы будете в конечном итоге работать с широкими строками, иногда вам потребуется преобразование между строками широких и многобайтовыми строками и эти помощники могут помочь вам:

// multi byte to wide char: 
std::wstring s2ws(const std::string& str) 
{ 
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); 
    std::wstring wstrTo(size_needed, 0); 
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); 
    return wstrTo; 
} 

// wide char to multi byte: 
std::string ws2s(const std::wstring& wstr) 
{ 
    int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), 0, 0, 0, 0); 
    std::string strTo(size_needed, 0); 
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), &strTo[0], size_needed, 0, 0); 
    return strTo; 
} 
+0

«Я рекомендую вам использовать Unicode». Конечно, использование Unicode не исключает использование 'char *'. Обычно я кодирую данные Unicode как UTF-8 и придерживаюсь символом 'char *'. – bames53

+0

@ bames53: В зависимости от контекста программы, а также от API, которые он собирается использовать, но я признаю, что мультибайт кажется лучшим выбором здесь. – LihO

+1

@ bames53: Правда, но, к сожалению, для окон unicode более или менее подразумевается utf-16 и 'wchar_t', так как это использует win32 api. – user786653

-1

кроме чтения 26 000 страниц cpp 2003 руководство VS, которое не сильно изменилось .... std :: string test (print); test = "";

int _tmain(int argc, _TCHAR* argv[]) 

int main(int argc, char *argv[]) 

работы тот же, если вы не использовали некоторые securitys функции .... и не может быть юникода в свойстве алфавитов ... если бы вы использовали функцию CreateFile в функции управления файл, если только вам несколько -прочитал его как-то

Смежные вопросы