Skip to content
C++ Better Explained
Go back
How to Fix C4996 'This function or variable may be unsafe' in Visual Studio

How to Fix C4996 “This function or variable may be unsafe” in Visual Studio

Short answer: Visual Studio flags older C functions such as scanf, strcpy and fopen. Many of them can write past the end of an array if they’re used carelessly. C4996 is a warning, but with SDL checks on, it becomes an error and your program won’t build. In C++, the best fix is to use std::cin, std::string and std::ifstream instead. To keep the C function, use the _s version it suggests, or put #define _CRT_SECURE_NO_WARNINGS above all your #include lines.

You seeWhat it means
error C4996: 'scanf': This function or variable may be unsafe...SDL checks are on, so the warning is treated as an error
warning C4996: 'scanf': This function or variable may be unsafe...The same message as a warning; the program still builds
Nothing, with GCC or ClangThese functions are standard C, and those compilers don’t flag them

Hit “This function or variable may be unsafe”? It's a classic beginner trap, and there are others like it.

Free 1-page checklist: The 10 Mistakes Every C++ Beginner Makes. It shows the exact traps that slow down every C++ beginner, so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


What the Message Says

Here’s the full message from a Visual Studio build:

error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

It names the function, suggests a replacement (scanf_s), and tells you how to switch the message off.

Microsoft’s documentation explains that most of the flagged functions can read or write a buffer without checking its size, so a careless call can run past the end of an array. That’s why safer _s versions exist. The message comes from Microsoft’s libraries, not from the C++ standard. GCC and Clang compile the same code without a word.

Why It’s an Error, Not a Warning

C4996 is officially a level 3 warning. You get error C4996 instead when your project has SDL checks turned on, which compiles with /sdl. Microsoft’s documentation lists C4996 among the warnings /sdl turns into errors.

To see the setting: Project > Properties > Configuration Properties > C/C++ > General > SDL checks.

Turning SDL checks off only turns the error back into a warning, and /sdl adds other safety checks you’d lose too. Fixing the code is the better choice.

Fix 1: Use the C++ Way (Best)

For the functions beginners meet most often, C++ has a replacement that Visual Studio doesn’t flag.

scanf → std::cin

#include <cstdio>

int main() {
    int age;
    scanf("%d", &age);
    printf("You are %d\n", age);
}
MSVC:   error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
#include <iostream>

int main() {
    int age;
    std::cin >> age;
    std::cout << "You are " << age << '\n';
}

strcpy → std::string

#include <cstring>
#include <iostream>

int main() {
    char name[20];
    strcpy(name, "Sam");
    std::cout << name << '\n';
}
MSVC:   error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

name has room for 19 characters plus the '\0' that ends the text. strcpy doesn’t check that. Copy in a longer name and it writes past the end of the array, into whatever memory comes next. That’s the danger the warning is about. A std::string grows to fit:

#include <iostream>
#include <string>

int main() {
    std::string name = "Sam";
    std::cout << name << '\n';
}

See string vs char array for the full comparison.

fopen → std::ifstream

#include <cstdio>

int main() {
    FILE* file = fopen("scores.txt", "r");
    if (file) {
        fclose(file);
    }
}
MSVC:   error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
#include <fstream>
#include <iostream>

int main() {
    std::ifstream file("scores.txt");
    if (!file) {
        std::cout << "Could not open scores.txt\n";
    }
}

More in file handling in C++.

Want to see where your data actually lives? C++ Better Explained uses diagrams and plain-English analogies to explain the stack, the heap, new and delete, and smart pointers.

Get the book — $19

Fix 2: Use the _s Version

If you’re writing C-style code on purpose, use the function the message suggests. The _s versions take extra information, usually the size of your buffer, so they can stop before running past the end:

#include <cstring>
#include <iostream>

int main() {
    char name[20];
    strcpy_s(name, sizeof(name), "Sam");
    std::cout << name << '\n';
}

For numbers, scanf_s("%d", &age); works exactly like scanf. For text, it’s different: with %s, %c or %[, Microsoft’s documentation says you must pass the buffer size as an extra argument straight after the buffer, for example scanf_s("%19s", name, (unsigned)sizeof(name));.

The catch is that these functions come from Microsoft’s runtime. GCC and Clang on Linux don’t provide them, so this code won’t build there: GCC says 'strcpy_s' was not declared in this scope. If your code needs to build on other systems as well, prefer Fix 1.

Fix 3: Turn the Warning Off

If you understand the risk and want to keep the original functions, for example to follow a C course or book, you can switch C4996 off.

Define _CRT_SECURE_NO_WARNINGS before every #include:

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

int main() {
    int age;
    scanf("%d", &age);
}

It has to come first. This version still gives C4996:

#include <cstdio>
#define _CRT_SECURE_NO_WARNINGS

int main() {
    int age;
    scanf("%d", &age);
}

The header checks for the macro when it’s included, so a #define after the #include comes too late.

Or set it for the whole project: Project > Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions, and add _CRT_SECURE_NO_WARNINGS. Use this if your .cpp files begin with #include "pch.h", or if you have several files to fix.

Or disable warning 4996 itself: add #pragma warning(disable : 4996) at the top of the file, or add 4996 under C/C++ > Advanced > Disable Specific Warnings. This hides every C4996, including ones about other deprecated features you might want to see, so the macro is the more targeted option.

The POSIX Version: getch and Friends

A second kind of C4996 has a different message:

#include <conio.h>
#include <iostream>

int main() {
    std::cout << "Press any key to exit...";
    getch();
}
MSVC:   error C4996: 'getch': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _getch. See online help for details.

This time only the name is deprecated, not the function. Fix: add the underscore and call _getch(). _CRT_SECURE_NO_WARNINGS doesn’t silence this version; the macro for POSIX names is _CRT_NONSTDC_NO_WARNINGS.

<conio.h> is Windows-only. MinGW’s GCC accepts getch() without complaint, but on Linux, GCC stops with fatal error: conio.h: No such file or directory.

Common C4996 Functions

FunctionSuggested replacementC++ alternative
scanfscanf_sstd::cin >> x
strcpy, strncpystrcpy_s, strncpy_sstd::string and =
strcatstrcat_sstd::string and +=
sprintfsprintf_sstd::to_string or std::ostringstream
fopenfopen_sstd::ifstream, std::ofstream
strtokstrtok_sstd::istringstream
localtime, ctimelocaltime_s, ctime_s
getenv_dupenv_s
getch_getch

The suggested replacements are the ones Visual Studio’s messages name. For splitting text without strtok, see how to split a string.

Quick Reference

The message saysFix
This function or variable may be unsafeUse the C++ alternative, the _s version, or #define _CRT_SECURE_NO_WARNINGS on the first line
The POSIX name for this item is deprecatedAdd the underscore (_getch), or define _CRT_NONSTDC_NO_WARNINGS
error C4996 rather than warning C4996SDL checks are on; fix the code rather than turning them off

For other common messages, see C++ error messages explained.


Take Your C++ Further

C++ Better Explained ebook cover

Memory bugs make much more sense once you can picture the stack and the heap. C++ Better Explained walks through how C++ manages memory, from new and delete to smart pointers, with diagrams and plain-English analogies.

Get the book — $19

87 pages · plain English · 30-day money-back guarantee


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Next Post
How to Fix Expected '}' at End of Input in C++

Keep Learning