Відповідь на ваше запитання залежить від того, на якій мові мови вона задається.
Мова, описана в довідковому посібнику Денніса Річі 1974 р. С, була мовою низького рівня, яка пропонувала деякі зручності програмування мов вищого рівня. Діалекти, похідні від цієї мови, також мали тенденцію бути мовами програмування низького рівня.
Коли було опубліковано Стандарт 1989/1990 С, він не описував мову низького рівня, яка стала популярною для програмування фактичних машин, а натомість описала мову вищого рівня, яка могла б бути, але не вимагається, -здійснюється в нижчому рівні.
Як зазначають автори стандарту C, однією з речей, яка зробила мову корисною, було те, що багато реалізацій можна розглядати як асемблери високого рівня. Оскільки C також використовувався як альтернатива іншим мовам високого рівня, і оскільки багато додатків не вимагали можливості робити те, чого не могли робити мови високого рівня, автори Standard дозволяли реалізаціям вести себе довільно якщо програми намагалися використовувати конструкції низького рівня. Отже, мова, описана стандартом C, ніколи не була мовою програмування низького рівня.
Щоб зрозуміти це розрізнення, подумайте, як мова Річі і C89 переглядатиме фрагмент коду:
struct foo { int x,y; float z; } *p;
...
p[3].y+=1;
на платформі, де "char" - 8 біт, "int" - 16 біт "big-endian", "float" - 32 біт, а структури не мають спеціальних вимог до вирівнювання або вирівнювання, тому розмір "struct foo" становить 8 байт.
У мові Річі поведінка останнього твердження прийме адресу, збережену в "p", додасть до неї 3 * 8 + 2 [тобто 26] байт і отримає 16-бітове значення з байтів за цією адресою та наступним , додайте до цього значення одне, а потім запишіть це 16-бітове значення на ті самі два байти. Поведінка буде визначена як дія 26-го та 27-го байтів, що слідує за адресою p, не зважаючи на те, який об’єкт там зберігався.
У мові, визначеній стандартом C, у випадку, якщо * p ідентифікує елемент "struct foo []", за яким слідують щонайменше ще три повноцінні елементи цього типу, останнє твердження додало б його до члена y третій елемент після * р. Поведінка не визначається Стандартом ні за яких інших обставин.
Мова Річі була мовою програмування низького рівня, оскільки, хоча вона дозволяла програмісту використовувати абстракції, як масиви та структури, коли це зручно, вона визначала поведінку з точки зору базового компонування об’єктів у пам'яті. Навпаки, мова, описана C89 та пізнішими стандартами, визначає речі з точки зору абстракції вищого рівня і лише визначає поведінку коду, яка відповідає цьому. Впровадження якості, придатне для програмування низького рівня, буде вести себе корисно у більшості випадків, ніж це передбачено Стандартом, але немає "офіційного" документа, який би вказував, що потрібно зробити, щоб придатність була такою метою.
Таким чином, мова С, винайдена Деннісом Річі, є мовою низького рівня і була визнана такою. Однак мова, винайдена Комітетом зі стандартів С, ніколи не була мовою низького рівня за відсутності гарантій, що забезпечуються впровадженням, що виходять за рамки мандатів Стандарту.