Southmountain Ответов: 2

Ошибка макроса TEXT() в консольном приложении проекта visual C++ в VS 2017


в Visual Studio 2017 я попробовал простой демонстрационный код из msdn Получение Системной Информации.

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

Error	C2440	'initializing': cannot convert from 'const wchar_t [18]' to 'TCHAR *'	SystemInfo2	c:\demo_temp\systeminfo2\systeminfo2\systeminfo2.cpp	11	


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

чтобы вам было удобно, я копирую демо-код здесь.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

TCHAR* envVarStrings[] =
{
  TEXT("OS         = %OS%"),
  TEXT("PATH       = %PATH%"),
  TEXT("HOMEPATH   = %HOMEPATH%"),
  TEXT("TEMP       = %TEMP%")
};
#define  ENV_VAR_STRING_COUNT  (sizeof(envVarStrings)/sizeof(TCHAR*))
#define INFO_BUFFER_SIZE 32767
void printError( TCHAR* msg );

void main( )
{
  DWORD i;
  TCHAR  infoBuf[INFO_BUFFER_SIZE];
  DWORD  bufCharCount = INFO_BUFFER_SIZE;
 
  // Get and display the name of the computer. 
  bufCharCount = INFO_BUFFER_SIZE;
  if( !GetComputerName( infoBuf, &bufCharCount ) )
    printError( TEXT("GetComputerName") ); 
  _tprintf( TEXT("\nComputer name:      %s"), infoBuf ); 
 
  // Get and display the user name. 
  bufCharCount = INFO_BUFFER_SIZE;
  if( !GetUserName( infoBuf, &bufCharCount ) )
    printError( TEXT("GetUserName") ); 
  _tprintf( TEXT("\nUser name:          %s"), infoBuf ); 
 
  // Get and display the system directory. 
  if( !GetSystemDirectory( infoBuf, INFO_BUFFER_SIZE ) )
    printError( TEXT("GetSystemDirectory") ); 
  _tprintf( TEXT("\nSystem Directory:   %s"), infoBuf ); 
 
  // Get and display the Windows directory. 
  if( !GetWindowsDirectory( infoBuf, INFO_BUFFER_SIZE ) )
    printError( TEXT("GetWindowsDirectory") ); 
  _tprintf( TEXT("\nWindows Directory:  %s"), infoBuf ); 
 
  // Expand and display a few environment variables. 
  _tprintf( TEXT("\n\nSmall selection of Environment Variables:") ); 
  for( i = 0; i < ENV_VAR_STRING_COUNT; ++i )
  {
    bufCharCount = ExpandEnvironmentStrings(envVarStrings[i], infoBuf,
        INFO_BUFFER_SIZE ); 
    if( bufCharCount > INFO_BUFFER_SIZE )
      _tprintf( TEXT("\n\t(Buffer too small to expand: \"%s\")"), 
              envVarStrings[i] );
    else if( !bufCharCount )
      printError( TEXT("ExpandEnvironmentStrings") );
    else
      _tprintf( TEXT("\n   %s"), infoBuf );
  }
  _tprintf( TEXT("\n\n"));
}

void printError( TCHAR* msg )
{
  DWORD eNum;
  TCHAR sysMsg[256];
  TCHAR* p;

  eNum = GetLastError( );
  FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | 
         FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL, eNum,
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
         sysMsg, 256, NULL );

  // Trim the end of the line and terminate it with a null
  p = sysMsg;
  while( ( *p > 31 ) || ( *p == 9 ) )
    ++p;
  do { *p-- = 0; } while( ( p >= sysMsg ) &&
                          ( ( *p == '.' ) || ( *p < 33 ) ) );

  // Display the message
  _tprintf( TEXT("\n\t%s failed with error %d (%s)"), msg, eNum, sysMsg );
}


Что я уже пробовал:

если включить заголовочный файл <winnt.h>, Я все равно получаю такие сообщения об ошибках.

Я уже настроил набор символов на Unicode, и это консольный проект.

Rick York

Я попросил номера строк в списках кодов здесь, как и многие другие сайты, и это еще один пример того, почему.

Какая из них-строка 11?

Southmountain

из окна сообщения об ошибке он показывает:
Строка 11: текст("OS = %OS%"),

Rick York

Разве нет макроса PCTSTR? Он расшифровывается как указатель на строку const T. Это const TCHAR *. Это очень удобно знать и использовать. Определите сами, если это не так.

Southmountain

очень хорошие мысли. Я еще раз проверю это. Спасибо!

2 Ответов

Рейтинг:
5

Stefan_Lang

Хотя все было эффективно сказано выше, вот как я отношусь к таким ошибкам:

Сначала я использую онлайн-компилятор. Мое предпочтение таково ГДБ онлайн отладчик | компилятор - код, компиляции, запуска, отладки онлайн С, С++[^Он может компилироваться на C и различных вариантах C++.

Затем я пробую урезанный сегмент кода настроенный так чтобы не зависеть от каких либо специфических вещей ОС:

#include <stdio.h>
char* envVarStrings[] = { "a", "b" };
#define  ENV_VAR_STRING_COUNT  (sizeof(envVarStrings)/sizeof(char *))
int main() {
    printf("# strings: %d", ENV_VAR_STRING_COUNT);
    return 0;
}
Когда я пытаюсь запустить этот сегмент компилятор заявляет
Цитата:
предупреждение: ISO C++ запрещает преобразование Строковой константы в ‘char*’ [-Wwrite-strings]
Следуя этому предупреждению я нашел вот это :предупреждение: ISO C++ запрещает преобразование Строковой константы в 'char*' [-Wwrite-strings] - переполнение стека[^].

Согласно этому, действительно отсутствует константа, как уже подозревал ОГ:
char const* envVarStrings[] = { "a", "b" };
Эта строка принимается без предупреждения.

Конечно, по той же причине вы также должны изменить свой макрос, чтобы использовать указатель const char.

Следующая ошибка, о которой сообщается в моем тестовом коде, заключается в том, что я пытался использовать ваш макрос в качестве int, поэтому я также добавил приведение типа к int, но это может быть не обязательно в вашем коде.

Наконец, как указал Шао Вун Вун в комментарии к решению 1, любая попытка передать один из строковых литералов функции также должна использовать указатели const char.

Следующий пример выполняется без предупреждений или ошибок:
#include <stdio.h>
const char* envVarStrings[] = { "a", "b" };
#define  ENV_VAR_STRING_COUNT  (int)(sizeof(envVarStrings)/sizeof(const char *))
void printError(const char* text)
{
    printf("error: %s\n", text);
}
int main() {
    printf("# strings: %d\n", ENV_VAR_STRING_COUNT);
    printError(envVarStrings[0]);
    return 0;
}



Конечно, вы можете просто выбрать компиляцию всего этого в виде кода на языке Си и забыть о мелком шрифте: вы можете получить некоторые предупреждения, но он должен компилироваться. на самом деле, я задавался вопросом, почему вы используете макрос вместо const? Очевидно, что это константа, и именно для этого существует const - если только вы не компилируете код на языке Си!

Tl.dr: Если вам нужен код C, он должен работать (с предупреждениями, в зависимости от версии). В противном случае, вы не должны использовать этот макрос! Не то чтобы это спасло бы вас от ошибки, но, по крайней мере, у вас была бы более краткая информация для определения фактической проблемы. Более того, используя современные концепции и возможности языка C++, вы могли бы избежать этих проблем:
#include <iostream>
#include <string>
std::string envVarStrings[] = { "a", "b" };
const int ENV_VAR_STRING_COUNT = (sizeof(envVarStrings)/sizeof(std::string));
void printError(std::string& text)
{
    std::cout << "Error: " << text << std::endl;
}
int main() {
    std::cout << "# strings: " << ENV_VAR_STRING_COUNT << std::endl;
    printError(envVarStrings[0]);
    return 0;
}
Обратите внимание, что хотя printError должен использовать аргумент const, опустить его здесь не проблема! Причина в том, что std::string скрывает уродливые детали, вызывающие проблемы, которые у вас были, а сам тип string довольно прост и прост в использовании!


Southmountain

мы высоко ценим вашу помощь. ваше объяснение укрепило мое понимание некоторых основных понятий языка Си++.

Рейтинг:
1

OriginalGriff

На первый взгляд - я не могу тестировать C++ в данный момент - вам нужно, чтобы массив был const указатели:

const TCHAR* envVarStrings[] =
{
  TEXT("OS         = %OS%"),
  TEXT("PATH       = %PATH%"),
  TEXT("HOMEPATH   = %HOMEPATH%"),
  TEXT("TEMP       = %TEMP%")
};


Southmountain

Салют оригинальному гриффу!
добавив "const" перед TCHAR*, я перекомпилировал этот проект. сообщение об ошибке отсчитывает время до 10 из 17.

первое сообщение об ошибке приведено ниже:

'void printError(TCHAR *)': cannot convert argument 1 from 'const wchar_t [12]' to 'TCHAR *'


ошибка находится в строке 32 как показано ниже и текст является заостренным:
	// Get and display the system directory. 
	if (!GetSystemDirectory(infoBuf, INFO_BUFFER_SIZE))
		printError(TEXT("GetSystemDirectory"));

Shao Voon Wong

Добавьте const к параметру printError как в объявлении, так и в определении функции.

void printError( const TCHAR* msg )