在向printf()提供错误的参数时: printf("%s", "foo", "bar"); 或通过提供错误类型的参数时: printf("%d", "foo"); GCC能够警告这些错误: $ gcc -Wformat printf_too_many_arguments.c printf_warnings.c: In function `main': printf_warnings.c:5: warning: too many arguments for format printf_warnings.c:5: warning: too many arguments for format $ gcc -Wformat printf_argument_of_wrong_type.c printf_warnings.c: In function `main': printf_warnings.c:5: warning: format `%d' expects t
以下是关于 printf 的编程技术问答
我已经注意到,当printf/sprintf函数的格式字符串中的转换说明符与相应参数的类型或计数不匹配时,许多C编译器发出警告. . 在我看来,这就像一个概念上断,因为C没有根据语言规范具有内置功能. 所有编译器都应该了解printf/sprintf是他们的原型,而不是其语义.我知道printf/sprintf是标准C函数,但它们却居住在一个单独的库中,您必须包括stdio.h才能导入其原型. 许多编译器所做的是分析可以在运行时提供的格式字符串. 上面有意义吗? 解决方案 "所有编译器都应该知道printf/sprintf是他们的原型,而不是其语义". 那是不正确的部分.就标准而言,C实施的任何部分都可以"允许"了解任何其他部分,并发布可能对用户有用的诊断.标准不需要编译器内在,这也不是这种特殊的诊断,但是它们肯定不禁止. 请注意,(就标准而言)标准库是特殊的,它不仅是任何旧的链接库.如果特定的实现/编译器甚至为用户提供了与标准库不同版本链接的机
如果我使用不良术语,请提前道歉. 当我在GDB下编译C ++应用程序并使用printf()时,它给了我很棒的警告,与格式字符串的一致性和通过的参数有关. 例如,此代码: printf("%s %s", "foo"); 导致编译器警告"格式的争论太少",这是超级使用的. 它还将发出有关格式字符串类型与参数类型的警告. 它必须检查格式字符串,并将其与所提供的参数类型进行了比较. - 这种编译时间内省是可以添加到普通源代码中的东西,还是需要将其汇编为GCC本身? fwiw这在OS x. 上的GCC 4.2.1下 解决方案 您可以为自己的printf样函数(以及scanf/strftime/strfmon样函数)做这样的事情: #define PRINTF_FORMAT_CHECK(format_index, args_index) __attribute__ ((__format__(printf, format_index, args_index)))
当C1>>和-Wall编译c0>> -Wall>在命令行上使用时,编译器会根据所使用的格式字符串警告错误的参数.例如,下面的代码将收到一条错误消息,说明格式指定的3个参数,但实际上您只通过了两个参数. printf("%d%d%d", 1, 2); 在将包装器写入printf()>时,您如何保留此功能?我能想到的一种功能或宏将是一种形式.但是简单的解析器也可以接受. 可以在stackoverflow上找到一些编写printf包装器的方法.两种常见方法是使用vprintf with varrintf 使用__builtin_apply .我尝试了这两种方法,没有用. 解决方案 您可以使用GCC 格式函数属性以检查与格式字符串的参数. extern int my_printf (void *my_object, const char *my_format, ...) __attribute__ ((format (printf, 2, 3)
这是一个代码: #include #include void MyPrintf(char const* format, va_list args); void MyVariadicPrintf(char const* format, ...); void MyPrintf(char const* format, va_list args) { vprintf(format, args); } void MyVariadicPrintf(char const* format, ...) { va_list args; va_start(args, format); MyPrintf(format, args); va_end(args); } int main(int, char*) { MyVariadicPrintf("%s" /* missing 2nd argument */);
我想删除我在代码的这一行中得到的警告, FILE *fil; char *imp; (...) fprintf(fil,imp); 事实是,当我这样做时,它会在文件上写入我想要的内容,但是如果我应用格式%s,则不会像这样 fprintf(fil, "%s", imp); 解决方案 此警告是GCC告诉您无法将格式字符串参数验证到printf样式函数(printf,fprintf ...等).当编译器无法手动窥视字符串并确保您在运行时的意图时,就会生成此警告.让我们看看几个示例. 案例1.可以在编译时验证此字符串,并且编译器将允许它不警告: printf("This string has no format"); 案例2:对于这种情况,编译器可以检测到您的格式指定符,并会引起不同的警告.在我的机器上说"警告:格式的争论很少". // This will most probably crash your machine printf("Not a s
仔细阅读了网络并弄乱了自己,我似乎无法将void*的目标(是字符串)转换为std :: string.我已经尝试按照此页面来使用sprintf(buffer, "%p", *((int *)point)); ,但无济于事.可悲的是,是的,我必须使用一个void*,因为这是SDL在其Userevent struct中使用的. 我用来填写对userevent的代码,对于感兴趣的人,是: std::string filename = "ResumeButton.png"; SDL_Event button_press; button_press.type = BUTTON_PRESS; button_press.user.data1 = &filename; SDL_PushEvent(&button_press); 有什么想法? 编辑:感谢您的所有响应,我只需要将void*扔到std :: string*.傻我.非常感谢你们! 解决方案 您只需要动态分配它(因为
在最近的一个问题中,有人提到,当用printf打印指针值时,呼叫者必须将指针投入到void *,就像这样: int *my_ptr = .... printf("My pointer is: %p", (void *)my_ptr); 在我的一生中,我不知道为什么.我找到了这个问题几乎是一样的.问题的答案是正确的 - 它解释说INT和指针不一定是相同的长度. 当然,这是正确的,但是当i 已经有一个指针时,就像上面的情况一样,为什么我应该从int *到void *呢? int *何时与void *不同?实际上,(void *)my_ptr什么时候生成与简单my_ptr不同的机器代码? 更新: 多个知识渊博的响应者引用了标准,称通过错误的类型可能会导致不确定的行为.如何?我希望printf("%p", (int *)ptr)和printf("%p", (void *)ptr)能够生成完全相同的堆栈框架.两个调用什么时候会产生不同的堆栈帧? 解决方案 %p转换说
我希望能够创建一种记录机制,该机制非常简单地将参数传递到printf,但是我需要语法突出显示和输入验证.这是我到目前为止的Log名称空间的轮廓. #pragma once #include "pch.h" namespace Log { // Determines whether to create the console window or not. // Turn off for before release. extern bool CreateConsoleWindow; // Initialisation. extern bool Init(); // Writes a line to the console, appended with \r\n. extern void WriteLine(const char* _Format, ...); // Writes a line to the
我们目前正在挖掘一些真正旧的C ++/CLI代码(旧语法.net beta),并有些惊讶地看到这样的东西: System::String ^source("Test-String"); printf("%s", source); 程序正确输出 Test-String 我们想知道,为什么可以将托管字符串源传递到printf - 更重要的是:为什么它可以工作?我不希望编译器会提供一些便利性,因为以下内容不起作用: System::String ^source("Test-String"); char pDest[256]; strcpy(pDest, source); 这会产生一个(某种程度上的预期)编译错误,说System::String^不能转换为const char*.因此,我唯一的真正解释是,通过托管引用VA_LIST会超过所有编译器检查,并欺骗本机代码将指针使用指向托管堆中.由于System::String的表示类似于内存中的char阵列,因此prin
我想使用Microsoft Visual Studio 2010中使用printf在C ++中打印出A size_t变量的值(我想在此特定代码中使用printf而不是 正确独立的平台方法是使用%zu,但这似乎在Visual Studio中不起作用.视觉工作室文档 library/vstudio/tcxf1dw6.aspx 告诉我我必须使用%Iu(使用大写i,而不是小写l). Microsoft在这里不遵循标准吗?还是自C99以来已更改了标准?还是C和C ++之间的标准是不同的(对我来说似乎很奇怪)? 解决方案 MS Visual Studio在VS2013之前不支持%zu printf specifier.从VS2013开始(例如_MSC_VER> = 1800)%zu 可用.. 作为替代方案,对于先前版本的Visual
ive获得了一个在Mac上编译出色的多平台项目,但是在Windows上,我所有带有A%s的Swprintf呼叫都在寻找WCHAR_T,而不是通过它传递.事实证明,M $认为使%s代表广泛的角色功能中的其他东西会很有趣. aspx" rel =" noreferrer"> http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx 无论如何,我正在寻找一个创造性的编码技巧,比将ifdef其他每个宽字符串呼叫结束要好 解决方案 更新:VS 2015 CTP6恢复了更改,Microsoft再次行事与标准不同. Visual Studio 14 CTP1 和后来的始终将%s视为狭窄的字符串(char*),除非您定义_CRT_STDIO_LEGACY_WIDE_SPECIFIERS.它还添加了t长度修改器扩展名,该扩展名映射到MS所谓的"自然"宽度.对于sprintf %Ts是char*,对于swprintf %Ts是wchar_
我有一个在Windows/Linux上运行的C ++程序.在Windows上,该程序与Visual Studio 2012和Linux一起编辑,并与GCC编辑.当使用sprintf Visual Studio转换为字符串时,使用与扎带的GCC编译器不同的圆形方法 - IE小数在5中. . Visual Studio编译器似乎可以执行一半远离零而GCC href =" https://en.wikipedia.org/wiki/rounding#round_half_to_even" rel =" noreferrer"> round nore dound aka银行家四舍五入. 圆甚至所需的行为. 是否可以更改Visual Studio/Windows中Sprintf格式字符串的舍入行为?因为我需要使圆形在两者之间保持持续的行为. 这是一个小样本C ++程序,说明上述行为: int main() { char buffer[100];
我最近接受了一个小的MCF C ++应用程序,显然处于工作状态.首先,我正在通过代码运行PC-LINT,而Lint抱怨Cstringt正在将其传递给格式.互联网上的意见似乎是分歧的.有人说,CSTING旨在处理此用例无错误的处理情况,但其他人(以及 解决方案 cstring已经过精心设计,以作为可变参数列表的一部分传递,因此可以安全地使用它.而且,您可以相当确定Microsoft会注意不要破坏这种特定的行为.所以我会说如果您愿意,您可以安全地继续使用它. 也就是说,我个人更喜欢演员.字符串类的行为并不是常见的行为(例如,std :: string否),而对于心理一致性,最好以"安全"的方式做. P.S.:请参阅此
gcc很好地提供引用上面的来源,-wformat基本上提供以下功能 检查对printf和scanf等的调用,以确保提供的参数具有适合指定格式字符串的类型,并且格式字符串中指定的转换很有意义. 到目前为止,我可以找到Microsoft的最接近的是 this Tarening 与使用%d进行64 vs 32位构建有关. 解决方案 我相信这不是Visual Studio中的支持功能(我会尝试为此找到引用).我知道的最接近的是使用_Printf_format_string_ 其他解决方案 不幸的是,没有办法在编译时生成此类警告,但是VC ++代码分析工具将对带有不匹配参数的类似printf的功能生成警告消息. 请参阅VC ++和 http://sdn .microsoft.com/en-us/library/vstudio/ms173498.aspx 有关更多详细信息. 作为附带说明,人们一直在抱怨这一点,所以也许Microsoft将来会做些事情: https:
a(很长),而我以前定期使用以下代码 - 然后在MSVC 6上 - 确定为具有variadic参数函数的字符串格式化所需的内存: void LogPrint(const char *pszFormat, ...) { int nBytes; char *pszBuffer; va_list args; va_start(args, pszFormat); nBytes = vsnprintf(0, 0, pszFormat, va); va_end(args); // error checking omitted for brevity pszBuffer = new char[nBytes + 1]; va_start(args, pszFormat); vsnprintf(pszBuffer, nBytes, pszFormat, va); v
" _"是什么意思?为什么Microsoft在开始时添加了此标记? 从_开始的全局名称空间中的 解决方案 标识符保留用于实现. _snprintf只是实现(Visual Studio)提供的功能.关于此基本原理,Visual Studio实现C89和snprintf是后来的C99标准的一部分. 除此之外,两个函数的语义在返回类型中都是不同的,snprintf中始终是格式化字符串所采用的字符数(是否在缓冲区中有足够的空间,而_snprintf>如果缓冲区中没有足够的空间,将返回负数. 也就是说,分配一个足够大的缓冲区以使您可以执行的输出: int size = snprintf( 0, 0, "%s %d\n", str, i ); char * buffer = malloc( size+1 ); snprintf( buffer, size+1, "%s %d\n", str, i ); 您不能用_snprintf做到这一点,因为该功能返回的唯一信息是当前大